mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-08-26 12:46:08 +00:00
ttrss: Add backup support
- Use backup hooks to dump and restore database. - Add functional test for backup and restore. Signed-off-by: James Valleroy <jvalleroy@mailbox.org> Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
parent
8a60581f3d
commit
1eed7d581d
@ -22,6 +22,7 @@ Configuration helper for Tiny Tiny RSS.
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import augeas
|
import augeas
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from plinth import action_utils
|
from plinth import action_utils
|
||||||
@ -29,6 +30,7 @@ from plinth import action_utils
|
|||||||
CONFIG_FILE = '/etc/tt-rss/config.php'
|
CONFIG_FILE = '/etc/tt-rss/config.php'
|
||||||
DEFAULT_FILE = '/etc/default/tt-rss'
|
DEFAULT_FILE = '/etc/default/tt-rss'
|
||||||
DATABASE_FILE = '/etc/tt-rss/database.php'
|
DATABASE_FILE = '/etc/tt-rss/database.php'
|
||||||
|
DB_BACKUP_FILE = '/var/lib/plinth/backups-data/ttrss-database.sql'
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
@ -40,6 +42,9 @@ def parse_arguments():
|
|||||||
subparsers.add_parser('setup', help='Setup Tiny Tiny RSS configuration')
|
subparsers.add_parser('setup', help='Setup Tiny Tiny RSS configuration')
|
||||||
subparsers.add_parser('enable', help='Enable Tiny Tiny RSS site')
|
subparsers.add_parser('enable', help='Enable Tiny Tiny RSS site')
|
||||||
subparsers.add_parser('disable', help='Disable Tiny Tiny RSS site')
|
subparsers.add_parser('disable', help='Disable Tiny Tiny RSS site')
|
||||||
|
subparsers.add_parser('dump-database', help='Dump database to file')
|
||||||
|
subparsers.add_parser('restore-database',
|
||||||
|
help='Restore database from file')
|
||||||
|
|
||||||
subparsers.required = True
|
subparsers.required = True
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
@ -120,6 +125,27 @@ def subcommand_disable(_):
|
|||||||
action_utils.service_disable('tt-rss')
|
action_utils.service_disable('tt-rss')
|
||||||
|
|
||||||
|
|
||||||
|
def subcommand_dump_database(_):
|
||||||
|
"""Dump database to file."""
|
||||||
|
os.makedirs(os.path.dirname(DB_BACKUP_FILE), exist_ok=True)
|
||||||
|
with open(DB_BACKUP_FILE, 'w') as db_backup_file:
|
||||||
|
_run_as_postgres(['pg_dump', 'ttrss'], stdout=db_backup_file)
|
||||||
|
|
||||||
|
|
||||||
|
def subcommand_restore_database(_):
|
||||||
|
"""Restore database from file."""
|
||||||
|
_run_as_postgres(['dropdb', 'ttrss'])
|
||||||
|
_run_as_postgres(['createdb', 'ttrss'])
|
||||||
|
with open(DB_BACKUP_FILE, 'r') as db_restore_file:
|
||||||
|
_run_as_postgres(['psql', '--dbname', 'ttrss'], stdin=db_restore_file)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_as_postgres(command, stdin=None, stdout=None):
|
||||||
|
"""Run a command as postgres user."""
|
||||||
|
command = ['sudo', '--user', 'postgres'] + command
|
||||||
|
subprocess.run(command, stdin=stdin, stdout=stdout, check=True)
|
||||||
|
|
||||||
|
|
||||||
def load_augeas():
|
def load_augeas():
|
||||||
"""Initialize Augeas."""
|
"""Initialize Augeas."""
|
||||||
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
@apps @ttrss @sso
|
@apps @ttrss @sso @backups
|
||||||
Feature: TT-RSS News Feed Reader
|
Feature: TT-RSS News Feed Reader
|
||||||
Run TT-RSS News Feed Reader.
|
Run TT-RSS News Feed Reader.
|
||||||
|
|
||||||
@ -28,6 +28,15 @@ Scenario: Enable ttrss application
|
|||||||
When I enable the ttrss application
|
When I enable the ttrss application
|
||||||
Then the ttrss service should be running
|
Then the ttrss service should be running
|
||||||
|
|
||||||
|
Scenario: Backup and restore ttrss
|
||||||
|
Given the ttrss application is enabled
|
||||||
|
And I subscribe to a feed
|
||||||
|
When I create a backup of the ttrss app data
|
||||||
|
And I unsubscribe from the feed
|
||||||
|
And I restore the ttrss app data backup
|
||||||
|
Then the ttrss service should be running
|
||||||
|
And I should be subscribed to the feed
|
||||||
|
|
||||||
Scenario: Disable ttrss application
|
Scenario: Disable ttrss application
|
||||||
Given the ttrss application is enabled
|
Given the ttrss application is enabled
|
||||||
When I disable the ttrss application
|
When I disable the ttrss application
|
||||||
|
|||||||
@ -240,3 +240,18 @@ def syncthing_assert_folder_present(browser, folder_name):
|
|||||||
@then(parsers.parse('syncthing folder {folder_name:w} should not be present'))
|
@then(parsers.parse('syncthing folder {folder_name:w} should not be present'))
|
||||||
def syncthing_assert_folder_not_present(browser, folder_name):
|
def syncthing_assert_folder_not_present(browser, folder_name):
|
||||||
assert not site.syncthing_folder_is_present(browser, folder_name)
|
assert not site.syncthing_folder_is_present(browser, folder_name)
|
||||||
|
|
||||||
|
|
||||||
|
@given('I subscribe to a feed')
|
||||||
|
def ttrss_subscribe(browser):
|
||||||
|
site.ttrss_subscribe(browser)
|
||||||
|
|
||||||
|
|
||||||
|
@when('I unsubscribe from the feed')
|
||||||
|
def ttrss_unsubscribe(browser):
|
||||||
|
site.ttrss_unsubscribe(browser)
|
||||||
|
|
||||||
|
|
||||||
|
@then('I should be subscribed to the feed')
|
||||||
|
def ttrss_assert_subscribed(browser):
|
||||||
|
assert site.ttrss_is_subscribed(browser)
|
||||||
|
|||||||
@ -578,3 +578,53 @@ def syncthing_remove_folder(browser, folder_name):
|
|||||||
remove_folder_dialog.find_by_xpath(remove_button_xpath).first.click()
|
remove_folder_dialog.find_by_xpath(remove_button_xpath).first.click()
|
||||||
|
|
||||||
eventually(lambda: not folder_dialog.visible)
|
eventually(lambda: not folder_dialog.visible)
|
||||||
|
|
||||||
|
|
||||||
|
def _ttrss_load_main_interface(browser):
|
||||||
|
"""Load the TT-RSS interface."""
|
||||||
|
access_url(browser, 'tt-rss')
|
||||||
|
overlay = browser.find_by_id('overlay')
|
||||||
|
eventually(lambda: not overlay.visible)
|
||||||
|
|
||||||
|
|
||||||
|
def _ttrss_is_feed_shown(browser, invert=False):
|
||||||
|
return browser.is_text_present('Planet Debian') != invert
|
||||||
|
|
||||||
|
|
||||||
|
def ttrss_subscribe(browser):
|
||||||
|
"""Subscribe to a feed in TT-RSS."""
|
||||||
|
_ttrss_load_main_interface(browser)
|
||||||
|
browser.find_by_text('Actions...').click()
|
||||||
|
browser.find_by_text('Subscribe to feed...').click()
|
||||||
|
browser.find_by_id(
|
||||||
|
'feedDlg_feedUrl').fill('https://planet.debian.org/atom.xml')
|
||||||
|
browser.find_by_text('Subscribe').click()
|
||||||
|
if browser.is_text_present('You are already subscribed to this feed.'):
|
||||||
|
browser.find_by_text('Cancel').click()
|
||||||
|
|
||||||
|
expand = browser.find_by_css('span.dijitTreeExpandoClosed')
|
||||||
|
if expand:
|
||||||
|
expand.first.click()
|
||||||
|
|
||||||
|
assert eventually(_ttrss_is_feed_shown, [browser])
|
||||||
|
|
||||||
|
|
||||||
|
def ttrss_unsubscribe(browser):
|
||||||
|
"""Unsubscribe from a feed in TT-RSS."""
|
||||||
|
_ttrss_load_main_interface(browser)
|
||||||
|
expand = browser.find_by_css('span.dijitTreeExpandoClosed')
|
||||||
|
if expand:
|
||||||
|
expand.first.click()
|
||||||
|
|
||||||
|
browser.find_by_text('Planet Debian').click()
|
||||||
|
browser.execute_script("quickMenuGo('qmcRemoveFeed')")
|
||||||
|
prompt = browser.get_alert()
|
||||||
|
prompt.accept()
|
||||||
|
|
||||||
|
assert eventually(_ttrss_is_feed_shown, [browser, True])
|
||||||
|
|
||||||
|
|
||||||
|
def ttrss_is_subscribed(browser):
|
||||||
|
"""Return whether subscribed to a feed in TT-RSS."""
|
||||||
|
_ttrss_load_main_interface(browser)
|
||||||
|
return browser.is_text_present('Planet Debian')
|
||||||
|
|||||||
@ -27,7 +27,7 @@ from plinth.menu import main_menu
|
|||||||
from plinth.modules.users import register_group
|
from plinth.modules.users import register_group
|
||||||
from plinth.utils import format_lazy
|
from plinth.utils import format_lazy
|
||||||
|
|
||||||
from .manifest import clients
|
from .manifest import backup, clients
|
||||||
|
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
@ -132,3 +132,13 @@ def diagnose():
|
|||||||
check_certificate=False))
|
check_certificate=False))
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def backup_pre(packet):
|
||||||
|
"""Save database contents."""
|
||||||
|
actions.superuser_run('ttrss', ['dump-database'])
|
||||||
|
|
||||||
|
|
||||||
|
def restore_post(packet):
|
||||||
|
"""Restore database contents."""
|
||||||
|
actions.superuser_run('ttrss', ['restore-database'])
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from plinth.modules.backups.api import validate as validate_backup
|
||||||
from plinth.clients import store_url, validate
|
from plinth.clients import store_url, validate
|
||||||
|
|
||||||
clients = validate([{
|
clients = validate([{
|
||||||
@ -41,3 +42,13 @@ clients = validate([{
|
|||||||
'url': '/tt-rss'
|
'url': '/tt-rss'
|
||||||
}]
|
}]
|
||||||
}])
|
}])
|
||||||
|
|
||||||
|
backup = validate_backup({
|
||||||
|
'data': {
|
||||||
|
'files': ['/var/lib/plinth/backups-data/ttrss-database.sql']
|
||||||
|
},
|
||||||
|
'secrets': {
|
||||||
|
'files': ['/etc/tt-rss/database.php']
|
||||||
|
},
|
||||||
|
'services': ['tt-rss']
|
||||||
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user