From 25c4aed9d77f9f09358fff18e0d22dfb04eaec08 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Thu, 23 Jul 2026 13:21:44 +0200 Subject: [PATCH] Honor Store credentials in all storetool commands --- .../bongo/storetool/BackupCommands.py | 11 +++--- .../bongo/storetool/CalendarCommands.py | 25 ++++++------- .../storetool/bongo/storetool/Connection.py | 35 +++++++++++++++++++ .../bongo/storetool/ContactCommands.py | 9 ++--- .../storetool/bongo/storetool/MailCommands.py | 9 ++--- .../bongo/storetool/StoreCommands.py | 9 ++--- .../storetool/bongo/storetool/TestCommands.py | 5 +-- .../storetool/tests/test_python3_runtime.py | 14 ++++++++ 8 files changed, 84 insertions(+), 33 deletions(-) create mode 100644 src/apps/storetool/bongo/storetool/Connection.py diff --git a/src/apps/storetool/bongo/storetool/BackupCommands.py b/src/apps/storetool/bongo/storetool/BackupCommands.py index cf65043..4a3ea7f 100644 --- a/src/apps/storetool/bongo/storetool/BackupCommands.py +++ b/src/apps/storetool/bongo/storetool/BackupCommands.py @@ -28,7 +28,8 @@ import posixpath import tarfile from bongo.cmdparse import Command -from bongo.store.StoreClient import DocTypes, StoreClient +from bongo.store.StoreClient import DocTypes +from bongo.storetool.Connection import connect_store _METADATA_PREFIX = "BONGO." @@ -123,9 +124,7 @@ class StoreBackupCommand(Command): usage="%prog %cmd []") def _connection(self, options): - return StoreClient( - options.user, options.store, host=options.host, - port=int(options.port), authPassword=options.password) + return connect_store(options) def BackupStore(self, options, output): store = self._connection(options) @@ -191,9 +190,7 @@ class StoreRestoreCommand(Command): usage="%prog %cmd []") def _connection(self, options): - return StoreClient( - options.user, options.store, host=options.host, - port=int(options.port), authPassword=options.password) + return connect_store(options) def RestoreProps(self, store, target, metadata): for name, value in _properties(metadata).items(): diff --git a/src/apps/storetool/bongo/storetool/CalendarCommands.py b/src/apps/storetool/bongo/storetool/CalendarCommands.py index 621c5d7..d2854c9 100644 --- a/src/apps/storetool/bongo/storetool/CalendarCommands.py +++ b/src/apps/storetool/bongo/storetool/CalendarCommands.py @@ -18,8 +18,9 @@ import bongo.table as table from bongo.cmdparse import Command from bongo.Contact import Contact from bongo.BongoError import BongoError -from bongo.store.StoreClient import DocTypes, StoreClient, CalendarACL +from bongo.store.StoreClient import DocTypes, CalendarACL from bongo.store.QueueClient import QueueClient +from bongo.storetool.Connection import connect_store def _smtp_eols(value): @@ -34,7 +35,7 @@ class CalendarsCommand(Command): summary="List the calendars in your store") def Run(self, options, args): - store = StoreClient(options.user, options.store) + store = connect_store(options) cols = ["subd?", "Name", "Url"] rows = [] @@ -65,7 +66,7 @@ class CalendarEventsCommand(Command): return cal def Run(self, options, args): - store = StoreClient(options.user, options.store) + store = connect_store(options) cols = ["Summary", "Start", "End"] rows = [] @@ -110,7 +111,7 @@ class EventsDeleteCommand(Command): summary="Delete all events in the store") def Run(self, options, args): - store = StoreClient(options.user, options.store) + store = connect_store(options) try: events = list(store.Events()) @@ -135,7 +136,7 @@ class EventsCleanupCommand(Command): summary="Delete any events not linked with calendars") def Run(self, options, args): - store = StoreClient(options.user, options.store) + store = connect_store(options) try: events = list(store.Events()) @@ -168,7 +169,7 @@ class CalendarDeleteCommand(Command): self.print_help() self.exit() - store = StoreClient(options.user, options.store) + store = connect_store(options) try: for calname in args: @@ -249,7 +250,7 @@ class CalendarPublishCommand(Command): doc = "\"/calendars/%s\"" % (args[0]) addresses = args[1:] - store = StoreClient(options.user, options.store) + store = connect_store(options) try: acl = CalendarACL(store.GetACL(doc)) @@ -274,7 +275,7 @@ class CalendarUnpublishCommand(Command): doc = "\"/calendars/%s\"" % (args[0]) addresses = args[1:] - store = StoreClient(options.user, options.store) + store = connect_store(options) try: acl = CalendarACL(store.GetACL(doc)) @@ -336,7 +337,7 @@ class CalendarShareCommand(Command): doc = "\"/calendars/%s\"" % (args[0]) addresses = args[1:] - store = StoreClient(options.user, options.store) + store = connect_store(options) try: info = store.Info(doc) @@ -372,7 +373,7 @@ class CalendarAcceptShareCommand(Command): docpath = "\"/calendars/%s\"" % (calname) - store = StoreClient(options.user, options.user) + store = connect_store(options, owner=options.user) try: cal = store.PropGet(docpath) @@ -407,7 +408,7 @@ class CalendarUnshareCommand(Command): doc = "\"/calendars/%s\"" % (args[0]) addresses = args[1:] - store = StoreClient(options.user, options.store) + store = connect_store(options) try: acl = CalendarACL(store.GetACL(doc)) @@ -437,7 +438,7 @@ class CalendarListSharesCommand(Command): doc = "\"/calendars/%s\"" % (args[0]) - store = StoreClient(options.user, options.store) + store = connect_store(options) try: acl = CalendarACL(store.GetACL(doc)) diff --git a/src/apps/storetool/bongo/storetool/Connection.py b/src/apps/storetool/bongo/storetool/Connection.py new file mode 100644 index 0000000..f95f7a0 --- /dev/null +++ b/src/apps/storetool/bongo/storetool/Connection.py @@ -0,0 +1,35 @@ +# /**************************************************************************** +# * +# * Copyright (c) 2001 Novell, Inc. All Rights Reserved. +# * +# * This program is free software; you can redistribute it and/or +# * modify it under the terms of version 2 of the GNU General Public License +# * as published by the Free Software Foundation. +# * +# * This program is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with this program; if not, contact Novell, Inc. +# * +# * To contact Novell about this file by physical or electronic mail, you +# * may find current contact information at www.novell.com. +# * +# ****************************************************************************/ + +"""Shared connection handling for every bongo-storetool command.""" + +from bongo.store.StoreClient import StoreClient + + +def connect_store(options, owner=None): + """Open a Store connection using the global command-line options.""" + return StoreClient( + options.user, + options.store if owner is None else owner, + host=options.host, + port=int(options.port), + authPassword=options.password, + ) diff --git a/src/apps/storetool/bongo/storetool/ContactCommands.py b/src/apps/storetool/bongo/storetool/ContactCommands.py index 7584d82..adb1dd5 100644 --- a/src/apps/storetool/bongo/storetool/ContactCommands.py +++ b/src/apps/storetool/bongo/storetool/ContactCommands.py @@ -6,7 +6,8 @@ import logging from bongo.cmdparse import Command from bongo.Contact import Contact -from bongo.store.StoreClient import DocTypes, StoreClient +from bongo.store.StoreClient import DocTypes +from bongo.storetool.Connection import connect_store class AddressbooksCommand(Command): log = logging.getLogger("Bongo.StoreTool") @@ -16,7 +17,7 @@ class AddressbooksCommand(Command): summary="List the addressbooks in your store") def Run(self, options, args): - store = StoreClient(options.user, options.store) + store = connect_store(options) cols = ["Name"] rows = [] @@ -49,7 +50,7 @@ class AddressbookContactsCommand(Command): self.print_help() self.exit() - store = StoreClient(options.user, options.store) + store = connect_store(options) cols = ["Name"] rows = [] @@ -87,7 +88,7 @@ class ImportVcfCommand(Command): self.print_usage() self.exit() - store = StoreClient(options.user, options.store) + store = connect_store(options) try: for file in args: diff --git a/src/apps/storetool/bongo/storetool/MailCommands.py b/src/apps/storetool/bongo/storetool/MailCommands.py index e6bf8ef..483b4b0 100644 --- a/src/apps/storetool/bongo/storetool/MailCommands.py +++ b/src/apps/storetool/bongo/storetool/MailCommands.py @@ -9,7 +9,8 @@ from gettext import gettext as _ from bongo.cmdparse import Command from bongo.BongoError import BongoError -from bongo.store.StoreClient import DocTypes, StoreClient +from bongo.store.StoreClient import DocTypes +from bongo.storetool.Connection import connect_store from bongo.storetool.ExportMailbox import MboxMailbox, MaildirMailbox class MailImportCommand(Command): @@ -56,7 +57,7 @@ class MailImportCommand(Command): self.print_help() self.exit() - store = StoreClient(options.user, options.store) + store = connect_store(options) try: for file in args: @@ -108,7 +109,7 @@ class MailExportCommand(Command): self.print_help() self.exit() - store = StoreClient(options.user, options.store) + store = connect_store(options) try: for file in args: @@ -140,7 +141,7 @@ class MailImapCommand(Command): self.print_help() self.exit() - store = StoreClient(options.user, options.store) + store = connect_store(options) try: self.ImportMail(store, options.folder, options.imap_username, options.imap_password, options.imap_folder, options.imap_server, options.imap_port) finally: diff --git a/src/apps/storetool/bongo/storetool/StoreCommands.py b/src/apps/storetool/bongo/storetool/StoreCommands.py index 8035c74..2a53d38 100644 --- a/src/apps/storetool/bongo/storetool/StoreCommands.py +++ b/src/apps/storetool/bongo/storetool/StoreCommands.py @@ -2,7 +2,8 @@ import logging import sys from bongo.cmdparse import Command -from bongo.store.StoreClient import DocTypes, StoreClient +from bongo.store.StoreClient import DocTypes +from bongo.storetool.Connection import connect_store def ParseDocumentType(value): @@ -23,7 +24,7 @@ class DocumentListCommand(Command): usage="%prog %cmd []") def Run(self, options, args): - store = StoreClient(options.user, options.store, host=options.host, port=int(options.port), authPassword=options.password) + store = connect_store(options) collection = '/' if len(args) > 0: @@ -48,7 +49,7 @@ class DocumentGetCommand(Command): usage="%prog %cmd [|-]") def Run(self, options, args): - store = StoreClient(options.user, options.store, host=options.host, port=int(options.port), authPassword=options.password) + store = connect_store(options) if len(args) == 0: self.print_help() @@ -81,7 +82,7 @@ class DocumentPutCommand(Command): usage="%prog %cmd []") def Run(self, options, args): - store = StoreClient(options.user, options.store, host=options.host, port=int(options.port), authPassword=options.password) + store = connect_store(options) if len(args) < 2: self.print_help() diff --git a/src/apps/storetool/bongo/storetool/TestCommands.py b/src/apps/storetool/bongo/storetool/TestCommands.py index 9637719..befcf1a 100644 --- a/src/apps/storetool/bongo/storetool/TestCommands.py +++ b/src/apps/storetool/bongo/storetool/TestCommands.py @@ -2,7 +2,8 @@ import logging from bongo import Xpl from bongo.cmdparse import Command from bongo.BongoError import BongoError -from bongo.store.StoreClient import DocTypes, StoreClient +from bongo.store.StoreClient import DocTypes +from bongo.storetool.Connection import connect_store class TestRun(Command): log = logging.getLogger("Bongo.StoreTool") @@ -17,7 +18,7 @@ class TestRun(Command): def Run(self, options, args): try: - store = StoreClient("admin", "admin") + store = connect_store(options) except: self.Err("Couldn't connect to a store for testing.") return diff --git a/src/apps/storetool/tests/test_python3_runtime.py b/src/apps/storetool/tests/test_python3_runtime.py index 2931802..a3a05f0 100644 --- a/src/apps/storetool/tests/test_python3_runtime.py +++ b/src/apps/storetool/tests/test_python3_runtime.py @@ -22,12 +22,15 @@ import io from pathlib import Path import tempfile +from types import SimpleNamespace import unittest +from unittest import mock from bongo import table from bongo.Console import wrap from bongo.external.simpletal import simpleTAL, simpleTALES from bongo.store.StoreClient import CalendarACL, StoreClient +from bongo.storetool.Connection import connect_store from bongo.storetool.ExportMailbox import MaildirMailbox, MboxMailbox @@ -54,6 +57,17 @@ class _Stream: class Python3RuntimeTests(unittest.TestCase): + @mock.patch("bongo.storetool.Connection.StoreClient") + def test_storetool_connection_uses_every_global_option(self, client): + options = SimpleNamespace( + user="alice", store="alice-store", host="store.example.test", + port="1689", password="secret") + + connect_store(options) + client.assert_called_once_with( + "alice", "alice-store", host="store.example.test", port=1689, + authPassword="secret") + def test_console_table_and_unicode_template_are_text(self): self.assertIsInstance(wrap("Grüße 世界", width=8), str) self.assertEqual(table.format_table(["Name"], [["Müller"]]),