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,47 @@
# Filesystem Storage Backup
Odoo addon: fs_storage_backup
## Installation
```bash
pip install odoo-bringout-oca-storage-fs_storage_backup
```
## Dependencies
This addon depends on:
- fs_storage
- mail
## Manifest Information
- **Name**: Filesystem Storage Backup
- **Version**: 16.0.1.0.1
- **Category**: Technical
- **License**: AGPL-3
- **Installable**: False
## Source
Based on [OCA/storage](https://github.com/OCA/storage) branch 16.0, addon `fs_storage_backup`.
## License
This package maintains the original AGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph Fs_storage_backup Module - fs_storage_backup
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for fs_storage_backup. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,3 @@
# Controllers
This module does not define custom HTTP controllers.

View file

@ -0,0 +1,6 @@
# Dependencies
This addon depends on:
- [fs_storage](../../odoo-bringout-oca-storage-fs_storage)
- [mail](../../odoo-bringout-oca-ocb-mail)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon fs_storage_backup or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-storage-fs_storage_backup"
# or
uv pip install odoo-bringout-oca-storage-fs_storage_backup"
```

View file

@ -0,0 +1,12 @@
# Models
Detected core models and extensions in fs_storage_backup.
```mermaid
classDiagram
class fs_storage
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: fs_storage_backup. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon fs_storage_backup
- License: LGPL-3

View file

@ -0,0 +1,3 @@
# Reports
This module does not define custom reports.

View file

@ -0,0 +1,8 @@
# Security
This module does not define custom security rules or access controls beyond Odoo defaults.
Default Odoo security applies:
- Base user access through standard groups
- Model access inherited from dependencies
- No custom row-level security rules

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon fs_storage_backup
```

View file

@ -0,0 +1,3 @@
# Wizards
This module does not include UI wizards.

View file

@ -0,0 +1,103 @@
=========================
Filesystem Storage Backup
=========================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3292ef4f97f5dcf8a5364cba204599da2169dd30020b9b488ddb72885f85f85b
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-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/16.0/fs_storage_backup
: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-fs_storage_backup
: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|
With this module you can configure one or more database backup
locations.
**Table of contents**
.. contents::
:local:
Configuration
=============
1. Go to Settings > Technical > FS Storage > FS Storage
2. Select a filesystem you want to use for backups. **NOTE: Make sure
you don't use the filestore as backup location otherwise it's
possible you'll back up the backup**
3. Enable ``Use For Backups``
4. Follow it (using the chatter) if you want to get notified when a
backup fails
5. To know if the backup is working correctly you can run the scheduled
action (``Backup database and delete old backups``) manually to test
it.
Usage
=====
The backup is done automatically by a scheduled action
(``Backup database and delete old backups``).
Known issues / Roadmap
======================
- **Configurable backup frequency**: e.g. backup every 7 days in s3 and
every 4 hours on a FTP server.
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_storage_backup%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
-------
* Onestein
Contributors
------------
- Dennis Sluijk d.sluijk@onestein.nl (https://onestein.nl)
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/fs_storage_backup>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

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

View file

@ -0,0 +1,14 @@
{
"name": "Filesystem Storage Backup",
"category": "Technical",
"version": "16.0.1.0.1",
"license": "AGPL-3",
"author": "Onestein, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/storage",
"depends": ["fs_storage", "mail"],
"data": [
"data/ir_cron_data.xml",
"data/mail_message_subtype_data.xml",
"views/fs_storage_view.xml",
],
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record model="ir.cron" id="cron_backup_db">
<field name="name">Backup database and delete old backups</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active">True</field>
<field name="doall" eval="False" />
<field name="model_id" ref="fs_storage.model_fs_storage" />
<field name="state">code</field>
<field name="code">model.cron_backup_db()</field>
<field
name="nextcall"
eval="(datetime.now() + timedelta(days=1)).strftime('%Y-%m-%d 00:00:00')"
/>
</record>
</odoo>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record id="message_subtype_backup_failed" model="mail.message.subtype">
<field name="name">Backup Failed</field>
<field name="description">Backup failed</field>
<field name="res_model">fs.storage</field>
<field name="default" eval="True" />
</record>
<record id="message_subtype_cleanup_failed" model="mail.message.subtype">
<field name="name">Backup Cleanup Failed</field>
<field name="description">Failed to clean up old backups</field>
<field name="res_model">fs.storage</field>
<field name="default" eval="True" />
</record>
</odoo>

View file

@ -0,0 +1,177 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * fs_storage_backup
#
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: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_needaction
msgid "Action Needed"
msgstr "Potrebna akcija"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_attachment_count
msgid "Attachment Count"
msgstr "Broj priloga"
#. module: fs_storage_backup
#: model:mail.message.subtype,name:fs_storage_backup.message_subtype_cleanup_failed
msgid "Backup Cleanup Failed"
msgstr "Čišćenje sigurnosnih kopija neuspješno"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_dir
msgid "Backup Directory"
msgstr "Direktorij za sigurnosne kopije"
#. module: fs_storage_backup
#: model:mail.message.subtype,name:fs_storage_backup.message_subtype_backup_failed
msgid "Backup Failed"
msgstr "Backup nije uspio"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_filename_format
msgid "Backup Filename"
msgstr "Naziv datoteke sigurnosne kopije"
#. module: fs_storage_backup
#: model:ir.actions.server,name:fs_storage_backup.cron_backup_db_ir_actions_server
#: model:ir.cron,cron_name:fs_storage_backup.cron_backup_db
msgid "Backup database and delete old backups"
msgstr "Kreiraj sigurnosnu kopiju baze podataka i obriši stare kopije"
#. module: fs_storage_backup
#: model:mail.message.subtype,description:fs_storage_backup.message_subtype_backup_failed
msgid "Backup failed"
msgstr "Kreiranje sigurnosne kopije neuspješno"
#. module: fs_storage_backup
#: model_terms:ir.ui.view,arch_db:fs_storage_backup.fs_storage_form_view
msgid "Backups"
msgstr "Sigurnosne kopije"
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#, python-format
msgid "Database backup failed"
msgstr "Kreiranje sigurnosne kopije baze podataka neuspješno"
#. module: fs_storage_backup
#: model:ir.model,name:fs_storage_backup.model_fs_storage
msgid "FS Storage"
msgstr "FS skladište"
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#: model:mail.message.subtype,description:fs_storage_backup.message_subtype_cleanup_failed
#, python-format
msgid "Failed to clean up old backups"
msgstr "Neuspješno čišćenje starih sigurnosnih kopija"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_follower_ids
msgid "Followers"
msgstr "Pratioci"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_partner_ids
msgid "Followers (Partners)"
msgstr "Pratioci (Partneri)"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__has_message
msgid "Has Message"
msgstr "Ima poruku"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_needaction
msgid "If checked, new messages require your attention."
msgstr "Ako je zakačeno, nove poruke će zahtjevati vašu pažnju"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_has_error
msgid "If checked, some messages have a delivery error."
msgstr "Ako je označeno neke poruke mogu imati grešku u dostavi."
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_include_filestore
msgid "Include Filestore In Backup"
msgstr "Uključi skladište datoteka u sigurnosnu kopiju"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_is_follower
msgid "Is Follower"
msgstr "Pratilac"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_keep_time
msgid "Keep backups of (in days)"
msgstr "Čuvaj sigurnosne kopije (u danima)"
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#, python-format
msgid "Keep backups of (in days) must be greater or than 0."
msgstr "Čuvaj sigurnosne kopije (u danima) mora biti veće od 0."
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_main_attachment_id
msgid "Main Attachment"
msgstr "Glavna zakačka"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_has_error
msgid "Message Delivery error"
msgstr "Greška pri isporuci poruke"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_ids
msgid "Messages"
msgstr "Poruke"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_needaction_counter
msgid "Number of Actions"
msgstr "Broj akcija"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_has_error_counter
msgid "Number of errors"
msgstr "Broj grešaka"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_needaction_counter
msgid "Number of messages requiring action"
msgstr "Broj poruka koje zahtijevaju aktivnost"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_has_error_counter
msgid "Number of messages with delivery error"
msgstr "Broj poruka sa greškama pri isporuci"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__use_for_backup
msgid "Use For Backups"
msgstr "Koristi za sigurnosne kopije"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__website_message_ids
msgid "Website Messages"
msgstr "Poruke sa website-a"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__website_message_ids
msgid "Website communication history"
msgstr "Povijest komunikacije Web stranice"

View file

@ -0,0 +1,177 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * fs_storage_backup
#
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: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_needaction
msgid "Action Needed"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_attachment_count
msgid "Attachment Count"
msgstr ""
#. module: fs_storage_backup
#: model:mail.message.subtype,name:fs_storage_backup.message_subtype_cleanup_failed
msgid "Backup Cleanup Failed"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_dir
msgid "Backup Directory"
msgstr ""
#. module: fs_storage_backup
#: model:mail.message.subtype,name:fs_storage_backup.message_subtype_backup_failed
msgid "Backup Failed"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_filename_format
msgid "Backup Filename"
msgstr ""
#. module: fs_storage_backup
#: model:ir.actions.server,name:fs_storage_backup.cron_backup_db_ir_actions_server
#: model:ir.cron,cron_name:fs_storage_backup.cron_backup_db
msgid "Backup database and delete old backups"
msgstr ""
#. module: fs_storage_backup
#: model:mail.message.subtype,description:fs_storage_backup.message_subtype_backup_failed
msgid "Backup failed"
msgstr ""
#. module: fs_storage_backup
#: model_terms:ir.ui.view,arch_db:fs_storage_backup.fs_storage_form_view
msgid "Backups"
msgstr ""
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#, python-format
msgid "Database backup failed"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model,name:fs_storage_backup.model_fs_storage
msgid "FS Storage"
msgstr ""
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#: model:mail.message.subtype,description:fs_storage_backup.message_subtype_cleanup_failed
#, python-format
msgid "Failed to clean up old backups"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_follower_ids
msgid "Followers"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_partner_ids
msgid "Followers (Partners)"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__has_message
msgid "Has Message"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_needaction
msgid "If checked, new messages require your attention."
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_has_error
msgid "If checked, some messages have a delivery error."
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_include_filestore
msgid "Include Filestore In Backup"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_is_follower
msgid "Is Follower"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_keep_time
msgid "Keep backups of (in days)"
msgstr ""
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#, python-format
msgid "Keep backups of (in days) must be greater or than 0."
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_main_attachment_id
msgid "Main Attachment"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_has_error
msgid "Message Delivery error"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_ids
msgid "Messages"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_needaction_counter
msgid "Number of Actions"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_has_error_counter
msgid "Number of errors"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_needaction_counter
msgid "Number of messages requiring action"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_has_error_counter
msgid "Number of messages with delivery error"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__use_for_backup
msgid "Use For Backups"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__website_message_ids
msgid "Website Messages"
msgstr ""
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__website_message_ids
msgid "Website communication history"
msgstr ""

View file

@ -0,0 +1,180 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * fs_storage_backup
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-05-29 16:26+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: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_needaction
msgid "Action Needed"
msgstr "Azione richiesta"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_attachment_count
msgid "Attachment Count"
msgstr "Conteggio allegati"
#. module: fs_storage_backup
#: model:mail.message.subtype,name:fs_storage_backup.message_subtype_cleanup_failed
msgid "Backup Cleanup Failed"
msgstr "Pulitura backup fallita"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_dir
msgid "Backup Directory"
msgstr "Cartella backup"
#. module: fs_storage_backup
#: model:mail.message.subtype,name:fs_storage_backup.message_subtype_backup_failed
msgid "Backup Failed"
msgstr "Backup fallito"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_filename_format
msgid "Backup Filename"
msgstr "Nome file backup"
#. module: fs_storage_backup
#: model:ir.actions.server,name:fs_storage_backup.cron_backup_db_ir_actions_server
#: model:ir.cron,cron_name:fs_storage_backup.cron_backup_db
msgid "Backup database and delete old backups"
msgstr "Esegui backup del database e cancella i vecchi backup"
#. module: fs_storage_backup
#: model:mail.message.subtype,description:fs_storage_backup.message_subtype_backup_failed
msgid "Backup failed"
msgstr "Backup fallito"
#. module: fs_storage_backup
#: model_terms:ir.ui.view,arch_db:fs_storage_backup.fs_storage_form_view
msgid "Backups"
msgstr "Backup"
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#, python-format
msgid "Database backup failed"
msgstr "Backup del database non riuscito"
#. module: fs_storage_backup
#: model:ir.model,name:fs_storage_backup.model_fs_storage
msgid "FS Storage"
msgstr "Deposito FS"
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#: model:mail.message.subtype,description:fs_storage_backup.message_subtype_cleanup_failed
#, python-format
msgid "Failed to clean up old backups"
msgstr "Pulizia vecchi backup fallita"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_follower_ids
msgid "Followers"
msgstr "Seguito da"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_partner_ids
msgid "Followers (Partners)"
msgstr "Seguito da (partner)"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__has_message
msgid "Has Message"
msgstr "Ha un messaggio"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_needaction
msgid "If checked, new messages require your attention."
msgstr "Se selezionata, nuovi messaggi richiedono attenzione."
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_has_error
msgid "If checked, some messages have a delivery error."
msgstr "Se selezionata, alcuni messaggi hanno un errore di consegna."
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_include_filestore
msgid "Include Filestore In Backup"
msgstr "Includere Filestore nel backup"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_is_follower
msgid "Is Follower"
msgstr "Segue"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__backup_keep_time
msgid "Keep backups of (in days)"
msgstr "Mantenere backup per (in giorni)"
#. module: fs_storage_backup
#. odoo-python
#: code:addons/fs_storage_backup/models/fs_storage.py:0
#, python-format
msgid "Keep backups of (in days) must be greater or than 0."
msgstr "Mantenere il backup per (in giorni) deve essere 0 o maggiore."
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_main_attachment_id
msgid "Main Attachment"
msgstr "Allegato principale"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_has_error
msgid "Message Delivery error"
msgstr "Errore di consegna messaggio"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_ids
msgid "Messages"
msgstr "Messaggi"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_needaction_counter
msgid "Number of Actions"
msgstr "Numero di azioni"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__message_has_error_counter
msgid "Number of errors"
msgstr "Numero di errori"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_needaction_counter
msgid "Number of messages requiring action"
msgstr "Numero di messaggi che richiedono un'azione"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__message_has_error_counter
msgid "Number of messages with delivery error"
msgstr "Numero di messaggi con errore di consegna"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__use_for_backup
msgid "Use For Backups"
msgstr "Usa per backup"
#. module: fs_storage_backup
#: model:ir.model.fields,field_description:fs_storage_backup.field_fs_storage__website_message_ids
msgid "Website Messages"
msgstr "Messaggi sito web"
#. module: fs_storage_backup
#: model:ir.model.fields,help:fs_storage_backup.field_fs_storage__website_message_ids
msgid "Website communication history"
msgstr "Cronologia comunicazioni sito web"

View file

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

View file

@ -0,0 +1,116 @@
import logging
import traceback
from datetime import timedelta, timezone
from os import path
from odoo import _, api, fields, models, tools
from odoo.exceptions import ValidationError
from odoo.service import db
_logger = logging.getLogger(__name__)
class FSStorage(models.Model):
_name = "fs.storage"
_inherit = ["fs.storage", "mail.thread"] # Use queue_job_cron instead?
use_for_backup = fields.Boolean(string="Use For Backups")
backup_include_filestore = fields.Boolean(
string="Include Filestore In Backup",
)
backup_filename_format = fields.Char(
string="Backup Filename", default="backup-%(db)s-%(dt)s.%(ext)s"
)
backup_keep_time = fields.Integer(string="Keep backups of (in days)", default=7)
backup_dir = fields.Char(string="Backup Directory", default="backups")
@property
def _server_env_fields(self):
env_fields = super()._server_env_fields
env_fields.update(
{
"use_for_backup": {},
"backup_include_filestore": {},
"backup_filename_format": {"no_default_field": False},
"backup_keep_time": {"no_default_field": False},
"backup_dir": {"no_default_field": False},
}
)
return env_fields
@api.constrains("backup_keep_time")
def _constrain_backup_keep_time(self):
if self.backup_keep_time < 1:
raise ValidationError(
_("Keep backups of (in days) must be greater or than 0.")
)
def _get_backup_format(self):
self.ensure_one()
return self.backup_include_filestore and "zip" or "dump"
def _get_backup_path(self):
self.ensure_one()
file_ext = self._get_backup_format()
current_datetime = fields.Datetime.now().strftime("%Y%m%d%H%M%S")
return path.join(
self.backup_dir,
self.backup_filename_format
% {"db": self.env.cr.dbname, "dt": current_datetime, "ext": file_ext},
)
def backup_db(self):
self.ensure_one()
try:
backup_path = self._get_backup_path()
self.fs.makedirs(self.backup_dir, exist_ok=True)
if self.fs.exists(backup_path):
raise Exception("File already exists (%s)." % backup_path)
backup_file = self.fs.open(backup_path, "w")
list_db = tools.config["list_db"]
if not list_db:
tools.config["list_db"] = True
db.dump_db(
self.env.cr.dbname,
backup_file.buffer,
backup_format=self._get_backup_format(),
)
tools.config["list_db"] = list_db
except Exception as e:
_logger.exception("Database backup failed: %s", e)
self.message_post(
subject=_("Database backup failed"),
body="<pre>%s</pre>" % tools.html_escape(traceback.format_exc()),
subtype_id=self.env.ref(
"fs_storage_backup.message_subtype_backup_failed"
).id,
)
def cleanup_old_backups(self):
self.ensure_one()
expiry_date = fields.Datetime.now() - timedelta(days=self.backup_keep_time)
try:
files = self.fs.ls(self.backup_dir, detail=False)
for file_path in files:
file_dt = self.fs.modified(file_path)
file_dt = file_dt.astimezone(timezone.utc)
file_dt = file_dt.replace(tzinfo=None)
if file_dt < expiry_date:
self.fs.rm(file_path)
except Exception as e:
_logger.exception("Failed to clean up old backups: %s", e)
self.message_post(
subject=_("Failed to clean up old backups"),
body="<pre>%s</pre>" % tools.html_escape(traceback.format_exc()),
subtype_id=self.env.ref(
"fs_storage_backup.message_subtype_cleanup_failed"
).id,
)
@api.model
def cron_backup_db(self):
# use_for_backup is not searchable
storages = self.search([])
for storage in storages.filtered(lambda s: s.use_for_backup):
storage.backup_db()
storage.cleanup_old_backups()

View file

@ -0,0 +1,7 @@
1. Go to Settings > Technical > FS Storage > FS Storage
2. Select a filesystem you want to use for backups.
**NOTE: Make sure you don't use the filestore as backup location otherwise it's possible you'll back up the backup**
3. Enable `Use For Backups`
4. Follow it (using the chatter) if you want to get notified when a backup fails
5. To know if the backup is working correctly you can run the scheduled action
(`Backup database and delete old backups`) manually to test it.

View file

@ -0,0 +1 @@
- Dennis Sluijk <d.sluijk@onestein.nl> (https://onestein.nl)

View file

@ -0,0 +1 @@
With this module you can configure one or more database backup locations.

View file

@ -0,0 +1 @@
- **Configurable backup frequency**: e.g. backup every 7 days in s3 and every 4 hours on a FTP server.

View file

@ -0,0 +1 @@
The backup is done automatically by a scheduled action (`Backup database and delete old backups`).

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,454 @@
<!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>Filesystem Storage Backup</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="filesystem-storage-backup">
<h1 class="title">Filesystem Storage Backup</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3292ef4f97f5dcf8a5364cba204599da2169dd30020b9b488ddb72885f85f85b
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/storage/tree/16.0/fs_storage_backup"><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-fs_storage_backup"><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>With this module you can configure one or more database backup
locations.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-3">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<ol class="arabic simple">
<li>Go to Settings &gt; Technical &gt; FS Storage &gt; FS Storage</li>
<li>Select a filesystem you want to use for backups. <strong>NOTE: Make sure
you dont use the filestore as backup location otherwise its
possible youll back up the backup</strong></li>
<li>Enable <tt class="docutils literal">Use For Backups</tt></li>
<li>Follow it (using the chatter) if you want to get notified when a
backup fails</li>
<li>To know if the backup is working correctly you can run the scheduled
action (<tt class="docutils literal">Backup database and delete old backups</tt>) manually to test
it.</li>
</ol>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<p>The backup is done automatically by a scheduled action
(<tt class="docutils literal">Backup database and delete old backups</tt>).</p>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h1>
<ul class="simple">
<li><strong>Configurable backup frequency</strong>: e.g. backup every 7 days in s3 and
every 4 hours on a FTP server.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-4">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:%20fs_storage_backup%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-5">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-6">Authors</a></h2>
<ul class="simple">
<li>Onestein</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<ul class="simple">
<li>Dennis Sluijk <a class="reference external" href="mailto:d.sluijk&#64;onestein.nl">d.sluijk&#64;onestein.nl</a> (<a class="reference external" href="https://onestein.nl">https://onestein.nl</a>)</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">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/fs_storage_backup">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 @@
from . import test_backup

View file

@ -0,0 +1,58 @@
from odoo.tests.common import TransactionCase
class TestBackup(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.fs_storage = cls.env.ref("fs_storage.default_fs_storage")
cls.fs_storage.use_for_backup = True
cls.fs_storage.backup_dir = "backups"
cls.fs_storage.backup_filename_format = "backup-%(db)s-%(dt)s.%(ext)s"
cls.fs_storage.backup_keep_time = 7
def test_with_filestore(self):
self.fs_storage.backup_include_filestore = True
old_counts = {}
for fs_storage in self.env["fs.storage"].search(
[("use_for_backup", "=", True)]
):
fs_storage.fs.makedirs(fs_storage.backup_dir, exist_ok=True)
old_counts[fs_storage.id] = len(
fs_storage.fs.ls(fs_storage.backup_dir, detail=False)
)
self.env["fs.storage"].cron_backup_db() # Backup all locations
for fs_storage in self.env["fs.storage"].search(
[("use_for_backup", "=", True)]
):
new_count = len(fs_storage.fs.ls(fs_storage.backup_dir, detail=False))
self.assertEqual(old_counts[fs_storage.id] + 1, new_count)
def test_without_filestore(self):
self.fs_storage.fs.makedirs(self.fs_storage.backup_dir, exist_ok=True)
files = self.fs_storage.fs.ls(self.fs_storage.backup_dir, detail=False)
old_count = len(list(filter(lambda f: f.endswith(".dump"), files)))
self.fs_storage.backup_include_filestore = False
self.fs_storage.backup_db()
files = self.fs_storage.fs.ls(self.fs_storage.backup_dir, detail=False)
new_count = len(list(filter(lambda f: f.endswith(".dump"), files)))
self.assertEqual(old_count + 1, new_count)
def test_cleanup_no_dir(self):
self.fs_storage.backup_dir = "backups123"
with self.assertLogs(level="ERROR"):
self.fs_storage.cleanup_old_backups()
def test_no_connection(self):
fs_storage = self.env["fs.storage"].create(
{
"name": "FTP",
"code": "ftp",
"protocol": "ftp",
"directory_path": ".",
"options": '{"host": "host", "port": 21}', # Non existent host
"use_for_backup": True,
}
)
with self.assertLogs(level="ERROR"):
fs_storage.backup_db()

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="fs_storage_form_view" model="ir.ui.view">
<field name="inherit_id" ref="fs_storage.fs_storage_form_view" />
<field name="model">fs.storage</field>
<field name="arch" type="xml">
<xpath expr="//field[@name='options']" position="after">
<separator string="Backups" />
<field name="use_for_backup" />
<field
name="backup_include_filestore"
attrs="{'invisible': [('use_for_backup', '=', False)]}"
/>
<field
name="backup_dir"
attrs="{'invisible': [('use_for_backup', '=', False)]}"
/>
<field
name="backup_filename_format"
attrs="{'invisible': [('use_for_backup', '=', False)]}"
/>
<field
name="backup_keep_time"
attrs="{'invisible': [('use_for_backup', '=', False)]}"
/>
</xpath>
<xpath expr="//sheet" position="after">
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="message_ids" widget="mail_thread" />
</div>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,43 @@
[project]
name = "odoo-bringout-oca-storage-fs_storage_backup"
version = "16.0.0"
description = "Filesystem Storage Backup - Odoo addon"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-storage-fs_storage>=16.0.0",
"odoo-bringout-oca-ocb-mail>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["fs_storage_backup"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]