Initial commit: OCA Storage packages (17 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:06 +02:00
commit 7a380f05d3
659 changed files with 41828 additions and 0 deletions

View file

@ -0,0 +1,82 @@
==============
Storage Bakend
==============
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e06faaef8e877cb770756ffc80fe1426d83d0130f6f1c239e9f16995156676ed
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status
:alt: Production/Stable
.. |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/16.0/storage_backend
:alt: OCA/storage
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/storage-16-0/storage-16-0-storage_backend
: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=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
**Table of contents**
.. contents::
:local:
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:%20storage_backend%0Aversion:%2016.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
~~~~~~~
* Akretion
Contributors
~~~~~~~~~~~~
* Sébastien BEAU <sebastien.beau@akretion.com>
* Raphaël Reverdy <raphael.reverdy@akretion.com>
* Florian da Costa <florian.dacosta@akretion.com>
* Cédric Pigeon <cedric.pigeon@acsone.eu>
* Renato Lima <renato.lima@akretion.com>
* Benoît Guillot <benoit.guillot@akretion.com>
* Laurent Mignon <laurent.mignon@acsone.eu>
* Denis Roussel <denis.roussel@acsone.eu>
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.
This module is part of the `OCA/storage <https://github.com/OCA/storage/tree/16.0/storage_backend>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,2 @@
from . import models
from . import components

View file

@ -0,0 +1,21 @@
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
{
"name": "Storage Bakend",
"summary": "Implement the concept of Storage with amazon S3, sftp...",
"version": "16.0.1.1.0",
"category": "Storage",
"website": "https://github.com/OCA/storage",
"author": " Akretion, Odoo Community Association (OCA)",
"license": "LGPL-3",
"development_status": "Production/Stable",
"installable": True,
"depends": ["base", "component", "server_environment"],
"data": [
"views/backend_storage_view.xml",
"data/data.xml",
"security/ir.model.access.csv",
],
}

View file

@ -0,0 +1,2 @@
from . import base_adapter
from . import filesystem_adapter

View file

@ -0,0 +1,69 @@
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
# Copyright 2020 ACSONE SA/NV (<http://acsone.eu>)
# @author Simone Orsi <simahawk@gmail.com>
import os
import re
from odoo.addons.component.core import AbstractComponent
class BaseStorageAdapter(AbstractComponent):
_name = "base.storage.adapter"
_collection = "storage.backend"
def _fullpath(self, relative_path):
dp = self.collection.directory_path
if not dp or relative_path.startswith(dp):
return relative_path
return os.path.join(dp, relative_path)
def add(self, relative_path, data, **kwargs):
raise NotImplementedError
def get(self, relative_path, **kwargs):
raise NotImplementedError
def list(self, relative_path=""):
raise NotImplementedError
def find_files(self, pattern, relative_path="", **kwargs):
"""Find files matching given pattern.
:param pattern: regex expression
:param relative_path: optional relative path containing files
:return: list of file paths as full paths from the root
"""
regex = re.compile(pattern)
filelist = self.list(relative_path)
files_matching = [
regex.match(file_).group() for file_ in filelist if regex.match(file_)
]
filepaths = []
if files_matching:
filepaths = [
os.path.join(self._fullpath(relative_path) or "", filename)
for filename in files_matching
]
return filepaths
def move_files(self, files, destination_path, **kwargs):
"""Move files to given destination.
:param files: list of file paths to be moved
:param destination_path: directory path where to move files
:return: None
"""
raise NotImplementedError
def delete(self, relative_path):
raise NotImplementedError
# You can define `validate_config` on your own adapter
# to make validation button available on UI.
# This method should simply pass smoothly when validation is ok,
# otherwise it should raise an exception.
# def validate_config(self):
# raise NotImplementedError

View file

@ -0,0 +1,76 @@
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import logging
import os
import shutil
from odoo import _
from odoo.exceptions import AccessError
from odoo.addons.component.core import Component
_logger = logging.getLogger(__name__)
def is_safe_path(basedir, path):
return os.path.realpath(path).startswith(basedir)
class FileSystemStorageBackend(Component):
_name = "filesystem.adapter"
_inherit = "base.storage.adapter"
_usage = "filesystem"
def _basedir(self):
return os.path.join(self.env["ir.attachment"]._filestore(), "storage")
def _fullpath(self, relative_path):
"""This will build the full path for the file, we force to
store the data inside the filestore in the directory 'storage".
Becarefull if you implement your own custom path, end user
should never be able to write or read unwanted filesystem file"""
full_path = super(FileSystemStorageBackend, self)._fullpath(relative_path)
base_dir = self._basedir()
full_path = os.path.join(base_dir, full_path)
if not is_safe_path(base_dir, full_path):
raise AccessError(_("Access to %s is forbidden") % full_path)
return full_path
def add(self, relative_path, data, **kwargs):
full_path = self._fullpath(relative_path)
dirname = os.path.dirname(full_path)
if not os.path.isdir(dirname):
os.makedirs(dirname)
with open(full_path, "wb") as my_file:
my_file.write(data)
def get(self, relative_path, **kwargs):
full_path = self._fullpath(relative_path)
with open(full_path, "rb") as my_file:
data = my_file.read()
return data
def list(self, relative_path=""):
full_path = self._fullpath(relative_path)
if os.path.isdir(full_path):
return os.listdir(full_path)
return []
def delete(self, relative_path):
full_path = self._fullpath(relative_path)
try:
os.remove(full_path)
except FileNotFoundError:
_logger.warning("File not found in %s", full_path)
def move_files(self, files, destination_path):
result = []
for file_path in files:
if not os.path.exists(destination_path):
os.makedirs(destination_path)
filename = os.path.basename(file_path)
destination_file = os.path.join(destination_path, filename)
result.append(shutil.move(file_path, destination_file))
return result

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record id="default_storage_backend" model="storage.backend">
<field name="name">Filesystem Backend</field>
<field name="backend_type">filesystem</field>
</record>
</odoo>

View file

@ -0,0 +1,148 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * storage_backend
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/components/filesystem_adapter.py:0
#, python-format
msgid "Access to %s is forbidden"
msgstr "Pristup %s je zabranjen"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type
msgid "Backend Type"
msgstr "Tip pozadine"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_default
msgid "Backend Type Env Default"
msgstr "Zadano okruženje tipa pozadine"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_is_editable
msgid "Backend Type Env Is Editable"
msgstr "Tip pozadine okruženja se može uređivati"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Failed!"
msgstr "Provjera povezivanja nije uspjela!"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Succeeded!"
msgstr "Provjera povezivanja uspješna!"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_uid
msgid "Created by"
msgstr "Kreirao"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_date
msgid "Created on"
msgstr "Kreirano"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path
msgid "Directory Path"
msgstr "Putanja direktorija"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_default
msgid "Directory Path Env Default"
msgstr "Zadano okruženje putanje direktorija"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_is_editable
msgid "Directory Path Env Is Editable"
msgstr "Putanja direktorija okruženja se može uređivati"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__display_name
msgid "Display Name"
msgstr "Prikazani naziv"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Everything seems properly set up!"
msgstr "Sve izgleda ispravno postavljeno!"
#. module: storage_backend
#: model:ir.model.fields.selection,name:storage_backend.selection__storage_backend__backend_type__filesystem
msgid "Filesystem"
msgstr "Datotečni sustav"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__has_validation
msgid "Has Validation"
msgstr "Ima validaciju"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__id
msgid "ID"
msgstr "ID"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend____last_update
msgid "Last Modified on"
msgstr "Zadnje mijenjano"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_uid
msgid "Last Updated by"
msgstr "Zadnji ažurirao"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_date
msgid "Last Updated on"
msgstr "Zadnje ažurirano"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__name
msgid "Name"
msgstr "Naziv:"
#. module: storage_backend
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path_env_default
msgid "Relative path to the directory to store the file"
msgstr "Relativna putanja do direktorija za skladištenje datoteke"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__server_env_defaults
msgid "Server Env Defaults"
msgstr "Zadane vrijednosti server okruženja"
#. module: storage_backend
#: model:ir.actions.act_window,name:storage_backend.act_open_storage_backend_view
#: model:ir.model,name:storage_backend.model_storage_backend
#: model:ir.ui.menu,name:storage_backend.menu_storage
#: model:ir.ui.menu,name:storage_backend.menu_storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_search
msgid "Storage Backend"
msgstr "Pozadina skladištenja"
#. module: storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
msgid "Test connection"
msgstr "Testiraj vezu"

View file

@ -0,0 +1,151 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * storage_backend
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-10-29 00:15+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/components/filesystem_adapter.py:0
#, python-format
msgid "Access to %s is forbidden"
msgstr "El acceso a %s está prohibido"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type
msgid "Backend Type"
msgstr "Tipo de servidor"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_default
msgid "Backend Type Env Default"
msgstr "Tipo de servidor Ent Por defecto"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_is_editable
msgid "Backend Type Env Is Editable"
msgstr "El Tipo de Entorno del Servidor es Editable"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Failed!"
msgstr "¡Error en la Prueba de Conexión!"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Succeeded!"
msgstr "¡Conexión de Prueba Exitosa!"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_date
msgid "Created on"
msgstr "Creado el"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path
msgid "Directory Path"
msgstr "Ruta del Directorio"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_default
msgid "Directory Path Env Default"
msgstr "Ruta del Directorio Ent Predet"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_is_editable
msgid "Directory Path Env Is Editable"
msgstr "El Entorno de Ruta del Directorio es Editable"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__display_name
msgid "Display Name"
msgstr "Mostrar Nombre"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Everything seems properly set up!"
msgstr "¡Todo parece correctamente configurado!"
#. module: storage_backend
#: model:ir.model.fields.selection,name:storage_backend.selection__storage_backend__backend_type__filesystem
msgid "Filesystem"
msgstr "Sistema de archivos"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__has_validation
msgid "Has Validation"
msgstr "Tiene Validación"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__id
msgid "ID"
msgstr "ID(identificación)"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend____last_update
msgid "Last Modified on"
msgstr "Última Modifiación el"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_uid
msgid "Last Updated by"
msgstr "Última Actualización por"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_date
msgid "Last Updated on"
msgstr "Última Actualización el"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__name
msgid "Name"
msgstr "Nombre"
#. module: storage_backend
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path_env_default
msgid "Relative path to the directory to store the file"
msgstr "Ruta relativa al directorio para almacenar el archivo"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__server_env_defaults
msgid "Server Env Defaults"
msgstr "Valores por defecto del Entorno de Servidor"
#. module: storage_backend
#: model:ir.actions.act_window,name:storage_backend.act_open_storage_backend_view
#: model:ir.model,name:storage_backend.model_storage_backend
#: model:ir.ui.menu,name:storage_backend.menu_storage
#: model:ir.ui.menu,name:storage_backend.menu_storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_search
msgid "Storage Backend"
msgstr "Servidor de Almacenamiento"
#. module: storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
msgid "Test connection"
msgstr "Probar conexión"

View file

@ -0,0 +1,151 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * storage_backend
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-06-03 09:25+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.10.4\n"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/components/filesystem_adapter.py:0
#, python-format
msgid "Access to %s is forbidden"
msgstr "L'accesso a %s è vietato"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type
msgid "Backend Type"
msgstr "Tipo backend"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_default
msgid "Backend Type Env Default"
msgstr "Tipo backend ambiente predefinito"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_is_editable
msgid "Backend Type Env Is Editable"
msgstr "Il tipo backend ambiente è modificabile"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Failed!"
msgstr "Test connessione fallito!"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Succeeded!"
msgstr "Test connessione avvenuto con successo!"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_date
msgid "Created on"
msgstr "Creato il"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path
msgid "Directory Path"
msgstr "Percorso cartella"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_default
msgid "Directory Path Env Default"
msgstr "Percorso cartella ambiente predefinito"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_is_editable
msgid "Directory Path Env Is Editable"
msgstr "Percorso cartella ambiente è modificabile"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Everything seems properly set up!"
msgstr "Tutto sembra impostato correttamente!"
#. module: storage_backend
#: model:ir.model.fields.selection,name:storage_backend.selection__storage_backend__backend_type__filesystem
msgid "Filesystem"
msgstr "Filesystem"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__has_validation
msgid "Has Validation"
msgstr "Ha validazione"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__id
msgid "ID"
msgstr "ID"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__name
msgid "Name"
msgstr "Nome"
#. module: storage_backend
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path_env_default
msgid "Relative path to the directory to store the file"
msgstr "Percorso relativo alla cartella per archiviare il file"
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__server_env_defaults
msgid "Server Env Defaults"
msgstr "Predefiniti ambiente server"
#. module: storage_backend
#: model:ir.actions.act_window,name:storage_backend.act_open_storage_backend_view
#: model:ir.model,name:storage_backend.model_storage_backend
#: model:ir.ui.menu,name:storage_backend.menu_storage
#: model:ir.ui.menu,name:storage_backend.menu_storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_search
msgid "Storage Backend"
msgstr "Backend deposito"
#. module: storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
msgid "Test connection"
msgstr "Prova connessione"

View file

@ -0,0 +1,148 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * storage_backend
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/components/filesystem_adapter.py:0
#, python-format
msgid "Access to %s is forbidden"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type
msgid "Backend Type"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_default
msgid "Backend Type Env Default"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__backend_type_env_is_editable
msgid "Backend Type Env Is Editable"
msgstr ""
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Failed!"
msgstr ""
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Connection Test Succeeded!"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_uid
msgid "Created by"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__create_date
msgid "Created on"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path
msgid "Directory Path"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_default
msgid "Directory Path Env Default"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__directory_path_env_is_editable
msgid "Directory Path Env Is Editable"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__display_name
msgid "Display Name"
msgstr ""
#. module: storage_backend
#. odoo-python
#: code:addons/storage_backend/models/storage_backend.py:0
#, python-format
msgid "Everything seems properly set up!"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields.selection,name:storage_backend.selection__storage_backend__backend_type__filesystem
msgid "Filesystem"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__has_validation
msgid "Has Validation"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__id
msgid "ID"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend____last_update
msgid "Last Modified on"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_uid
msgid "Last Updated by"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__write_date
msgid "Last Updated on"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__name
msgid "Name"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path
#: model:ir.model.fields,help:storage_backend.field_storage_backend__directory_path_env_default
msgid "Relative path to the directory to store the file"
msgstr ""
#. module: storage_backend
#: model:ir.model.fields,field_description:storage_backend.field_storage_backend__server_env_defaults
msgid "Server Env Defaults"
msgstr ""
#. module: storage_backend
#: model:ir.actions.act_window,name:storage_backend.act_open_storage_backend_view
#: model:ir.model,name:storage_backend.model_storage_backend
#: model:ir.ui.menu,name:storage_backend.menu_storage
#: model:ir.ui.menu,name:storage_backend.menu_storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_search
msgid "Storage Backend"
msgstr ""
#. module: storage_backend
#: model_terms:ir.ui.view,arch_db:storage_backend.storage_backend_view_form
msgid "Test connection"
msgstr ""

View file

@ -0,0 +1 @@
from . import storage_backend

View file

@ -0,0 +1,185 @@
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# Copyright 2019 Camptocamp SA (http://www.camptocamp.com).
# @author Simone Orsi <simone.orsi@camptocamp.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import base64
import fnmatch
import functools
import inspect
import logging
import warnings
from odoo import _, fields, models
_logger = logging.getLogger(__name__)
# TODO: useful for the whole OCA?
def deprecated(reason):
"""Mark functions or classes as deprecated.
Emit warning at execution.
The @deprecated is used with a 'reason'.
.. code-block:: python
@deprecated("please, use another function")
def old_function(x, y):
pass
"""
def decorator(func1):
if inspect.isclass(func1):
fmt1 = "Call to deprecated class {name} ({reason})."
else:
fmt1 = "Call to deprecated function {name} ({reason})."
@functools.wraps(func1)
def new_func1(*args, **kwargs):
warnings.simplefilter("always", DeprecationWarning)
warnings.warn(
fmt1.format(name=func1.__name__, reason=reason),
category=DeprecationWarning,
stacklevel=2,
)
warnings.simplefilter("default", DeprecationWarning)
return func1(*args, **kwargs)
return new_func1
return decorator
class StorageBackend(models.Model):
_name = "storage.backend"
_inherit = ["collection.base", "server.env.mixin"]
_backend_name = "storage_backend"
_description = "Storage Backend"
name = fields.Char(required=True)
backend_type = fields.Selection(
selection=[("filesystem", "Filesystem")], required=True, default="filesystem"
)
directory_path = fields.Char(
help="Relative path to the directory to store the file"
)
has_validation = fields.Boolean(compute="_compute_has_validation")
def _compute_has_validation(self):
for rec in self:
if not rec.backend_type:
# with server_env
# this code can be triggered
# before a backend_type has been set
# get_adapter() can't work without backend_type
rec.has_validation = False
continue
adapter = rec._get_adapter()
rec.has_validation = hasattr(adapter, "validate_config")
@property
def _server_env_fields(self):
return {"backend_type": {}, "directory_path": {}}
def add(self, relative_path, data, binary=True, **kwargs):
if not binary:
data = base64.b64decode(data)
return self._forward("add", relative_path, data, **kwargs)
@deprecated("Use `add`")
def _add_bin_data(self, relative_path, data, **kwargs):
return self.add(relative_path, data, **kwargs)
@deprecated("Use `add` with `binary=False`")
def _add_b64_data(self, relative_path, data, **kwargs):
return self.add(relative_path, data, binary=False, **kwargs)
def get(self, relative_path, binary=True, **kwargs):
data = self._forward("get", relative_path, **kwargs)
if not binary and data:
data = base64.b64encode(data)
return data
@deprecated("Use `get` with `binary=False`")
def _get_b64_data(self, relative_path, **kwargs):
return self.get(relative_path, binary=False, **kwargs)
@deprecated("Use `get`")
def _get_bin_data(self, relative_path, **kwargs):
return self.get(relative_path, **kwargs)
def list_files(self, relative_path="", pattern=False):
names = self._forward("list", relative_path)
if pattern:
names = fnmatch.filter(names, pattern)
return names
@deprecated("Use `list_files`")
def _list(self, relative_path="", pattern=False):
return self.list_files(relative_path, pattern=pattern)
def find_files(self, pattern, relative_path="", **kw):
return self._forward("find_files", pattern, relative_path=relative_path)
@deprecated("Use `find_files`")
def _find_files(self, pattern, relative_path="", **kw):
return self.find_files(pattern, relative_path=relative_path, **kw)
def move_files(self, files, destination_path, **kw):
return self._forward("move_files", files, destination_path, **kw)
@deprecated("Use `move_files`")
def _move_files(self, files, destination_path, **kw):
return self.move_files(files, destination_path, **kw)
def delete(self, relative_path):
return self._forward("delete", relative_path)
@deprecated("Use `delete`")
def _delete(self, relative_path):
return self.delete(relative_path)
def _forward(self, method, *args, **kwargs):
_logger.debug(
"Backend Storage ID: %s type %s: %s file %s %s",
self.backend_type,
self.id,
method,
args,
kwargs,
)
self.ensure_one()
adapter = self._get_adapter()
return getattr(adapter, method)(*args, **kwargs)
def _get_adapter(self):
with self.work_on(self._name) as work:
return work.component(usage=self.backend_type)
def action_test_config(self):
if not self.has_validation:
raise AttributeError("Validation not supported!")
adapter = self._get_adapter()
try:
adapter.validate_config()
title = _("Connection Test Succeeded!")
message = _("Everything seems properly set up!")
msg_type = "success"
except Exception as err:
title = _("Connection Test Failed!")
message = str(err)
msg_type = "danger"
return {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"title": title,
"message": message,
"type": msg_type,
"sticky": False,
},
}

View file

@ -0,0 +1,8 @@
* Sébastien BEAU <sebastien.beau@akretion.com>
* Raphaël Reverdy <raphael.reverdy@akretion.com>
* Florian da Costa <florian.dacosta@akretion.com>
* Cédric Pigeon <cedric.pigeon@acsone.eu>
* Renato Lima <renato.lima@akretion.com>
* Benoît Guillot <benoit.guillot@akretion.com>
* Laurent Mignon <laurent.mignon@acsone.eu>
* Denis Roussel <denis.roussel@acsone.eu>

View file

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_storage_backend_edit,storage_backend edit,model_storage_backend,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_storage_backend_edit storage_backend edit model_storage_backend base.group_system 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,429 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Storage Bakend</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
: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.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
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 }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="storage-bakend">
<h1 class="title">Storage Bakend</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e06faaef8e877cb770756ffc80fe1426d83d0130f6f1c239e9f16995156676ed
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/storage/tree/16.0/storage_backend"><img alt="OCA/storage" src="https://img.shields.io/badge/github-OCA%2Fstorage-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/storage-16-0/storage-16-0-storage_backend"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/storage&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/storage/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/storage/issues/new?body=module:%20storage_backend%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-3">Authors</a></h2>
<ul class="simple">
<li>Akretion</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-4">Contributors</a></h2>
<ul class="simple">
<li>Sébastien BEAU &lt;<a class="reference external" href="mailto:sebastien.beau&#64;akretion.com">sebastien.beau&#64;akretion.com</a>&gt;</li>
<li>Raphaël Reverdy &lt;<a class="reference external" href="mailto:raphael.reverdy&#64;akretion.com">raphael.reverdy&#64;akretion.com</a>&gt;</li>
<li>Florian da Costa &lt;<a class="reference external" href="mailto:florian.dacosta&#64;akretion.com">florian.dacosta&#64;akretion.com</a>&gt;</li>
<li>Cédric Pigeon &lt;<a class="reference external" href="mailto:cedric.pigeon&#64;acsone.eu">cedric.pigeon&#64;acsone.eu</a>&gt;</li>
<li>Renato Lima &lt;<a class="reference external" href="mailto:renato.lima&#64;akretion.com">renato.lima&#64;akretion.com</a>&gt;</li>
<li>Benoît Guillot &lt;<a class="reference external" href="mailto:benoit.guillot&#64;akretion.com">benoit.guillot&#64;akretion.com</a>&gt;</li>
<li>Laurent Mignon &lt;<a class="reference external" href="mailto:laurent.mignon&#64;acsone.eu">laurent.mignon&#64;acsone.eu</a>&gt;</li>
<li>Denis Roussel &lt;<a class="reference external" href="mailto:denis.roussel&#64;acsone.eu">denis.roussel&#64;acsone.eu</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-5">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>
<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>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/storage/tree/16.0/storage_backend">OCA/storage</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,2 @@
from . import common
from . import test_filesystem

View file

@ -0,0 +1,78 @@
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import base64
from unittest import mock
from odoo.addons.component.tests.common import TransactionComponentCase
class BackendStorageTestMixin(object):
def _test_setting_and_getting_data(self):
# Check that the directory is empty
files = self.backend.list_files()
self.assertNotIn(self.filename, files)
# Add a new file
self.backend.add(
self.filename, self.filedata, mimetype="text/plain", binary=False
)
# Check that the file exist
files = self.backend.list_files()
self.assertIn(self.filename, files)
# Retrieve the file added
data = self.backend.get(self.filename, binary=False)
self.assertEqual(data, self.filedata)
# Delete the file
self.backend.delete(self.filename)
files = self.backend.list_files()
self.assertNotIn(self.filename, files)
def _test_setting_and_getting_data_from_root(self):
self._test_setting_and_getting_data()
def _test_setting_and_getting_data_from_dir(self):
self.backend.directory_path = self.case_with_subdirectory
self._test_setting_and_getting_data()
def _test_find_files(
self,
backend,
adapter_dotted_path,
mocked_filepaths,
pattern,
expected_filepaths,
):
with mock.patch(adapter_dotted_path + ".list") as mocked:
mocked.return_value = mocked_filepaths
res = backend.find_files(pattern)
self.assertEqual(sorted(res), sorted(expected_filepaths))
def _test_move_files(
self,
backend,
adapter_dotted_path,
filename,
destination_path,
expected_filepaths,
):
with mock.patch(adapter_dotted_path + ".move_files") as mocked:
mocked.return_value = expected_filepaths
res = backend.move_files(filename, destination_path)
self.assertEqual(sorted(res), sorted(expected_filepaths))
class CommonCase(TransactionComponentCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.backend = cls.env.ref("storage_backend.default_storage_backend")
cls.filedata = base64.b64encode(b"This is a simple file")
cls.filename = "test_file.txt"
cls.case_with_subdirectory = "subdirectory/here"
cls.demo_user = cls.env.ref("base.user_demo")

View file

@ -0,0 +1,65 @@
# Copyright 2017 Akretion (http://www.akretion.com).
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import os
from odoo.exceptions import AccessError
from .common import BackendStorageTestMixin, CommonCase
ADAPTER_PATH = (
"odoo.addons.storage_backend.components.filesystem_adapter.FileSystemStorageBackend"
)
class FileSystemCase(CommonCase, BackendStorageTestMixin):
def test_setting_and_getting_data_from_root(self):
self._test_setting_and_getting_data_from_root()
def test_setting_and_getting_data_from_dir(self):
self._test_setting_and_getting_data_from_dir()
def test_find_files(self):
good_filepaths = ["somepath/file%d.good" % x for x in range(1, 10)]
bad_filepaths = ["somepath/file%d.bad" % x for x in range(1, 10)]
mocked_filepaths = bad_filepaths + good_filepaths
backend = self.backend.sudo()
base_dir = backend._get_adapter()._basedir()
expected = [base_dir + "/" + path for path in good_filepaths]
self._test_find_files(
backend, ADAPTER_PATH, mocked_filepaths, r".*\.good$", expected
)
def test_move_files(self):
backend = self.backend.sudo()
base_dir = backend._get_adapter()._basedir()
expected = [base_dir + "/" + self.filename]
destination_path = os.path.join(base_dir, "destination")
self._test_move_files(
backend, ADAPTER_PATH, self.filename, destination_path, expected
)
class FileSystemDemoUserAccessCase(CommonCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.backend = cls.backend.with_user(cls.demo_user)
def test_cannot_add_file(self):
with self.assertRaises(AccessError):
self.backend.add(
self.filename, self.filedata, mimetype="text/plain", binary=False
)
def test_cannot_list_file(self):
with self.assertRaises(AccessError):
self.backend.list_files()
def test_cannot_read_file(self):
with self.assertRaises(AccessError):
self.backend.get(self.filename, binary=False)
def test_cannot_delete_file(self):
with self.assertRaises(AccessError):
self.backend.delete(self.filename)

View file

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="storage_backend_view_tree" model="ir.ui.view">
<field name="model">storage.backend</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="backend_type" />
</tree>
</field>
</record>
<record id="storage_backend_view_form" model="ir.ui.view">
<field name="model">storage.backend</field>
<field name="arch" type="xml">
<form string="Storage Backend">
<header>
<field name="has_validation" invisible="1" />
<button
type="object"
name="action_test_config"
string="Test connection"
attrs="{'invisible': [('has_validation', '=', False)]}"
/>
</header>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only" />
<h1>
<field name="name" />
</h1>
</div>
<group name="config">
<field name="backend_type" />
<field name="directory_path" />
</group>
</sheet>
</form>
</field>
</record>
<record id="storage_backend_view_search" model="ir.ui.view">
<field name="model">storage.backend</field>
<field name="arch" type="xml">
<search string="Storage Backend">
<field name="name" />
</search>
</field>
</record>
<record model="ir.actions.act_window" id="act_open_storage_backend_view">
<field name="name">Storage Backend</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">storage.backend</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="storage_backend_view_search" />
<field name="domain">[]</field>
<field name="context">{}</field>
</record>
<record model="ir.actions.act_window.view" id="act_open_storage_backend_view_form">
<field name="act_window_id" ref="act_open_storage_backend_view" />
<field name="sequence" eval="20" />
<field name="view_mode">form</field>
<field name="view_id" ref="storage_backend_view_form" />
</record>
<record model="ir.actions.act_window.view" id="act_open_storage_backend_view_tree">
<field name="act_window_id" ref="act_open_storage_backend_view" />
<field name="sequence" eval="10" />
<field name="view_mode">tree</field>
<field name="view_id" ref="storage_backend_view_tree" />
</record>
<menuitem
id="menu_storage"
parent="base.menu_custom"
sequence="100"
action="act_open_storage_backend_view"
/>
<menuitem
id="menu_storage_backend"
parent="menu_storage"
sequence="10"
action="act_open_storage_backend_view"
/>
</odoo>