From 068f6339b419255ba4abda9431fc0e6136b68bbd Mon Sep 17 00:00:00 2001 From: Timo Kankare Date: Tue, 20 Sep 2016 22:06:48 +0300 Subject: [PATCH] Using backend specific parameter definitions to store backend settings. --- Mailnag/backends/__init__.py | 42 +++++++++++++-------- Mailnag/common/accounts.py | 53 +++++++++++++++++++------- tests/test_account.py | 72 ++++++++++++++++++++++++++++++++++++ tests/test_accountmanager.py | 31 +++++++++++++++- 4 files changed, 168 insertions(+), 30 deletions(-) create mode 100644 tests/test_account.py diff --git a/Mailnag/backends/__init__.py b/Mailnag/backends/__init__.py index 6263fad..83e9521 100644 --- a/Mailnag/backends/__init__.py +++ b/Mailnag/backends/__init__.py @@ -39,32 +39,42 @@ def _str_to_folders(folders_str): return folders +def _folders_to_str(folders): + return json.dumps(folders) + + def _str_to_bool(string): return bool(int(string)) -Param = namedtuple('Param', ['param_name', 'option_name', 'from_str', 'default_value']) +def _bool_to_str(b): + return str(int(b)) + + +Param = namedtuple('Param', + ['param_name', 'option_name', 'from_str', 'to_str', 'default_value'] +) Backend = namedtuple('Backend', ['backend_class', 'params']) _backends = { 'imap' : Backend(IMAPMailboxBackend, [ - Param('user', 'user', str, ''), - Param('password', 'password', str, ''), - Param('server', 'server', str, ''), - Param('port', 'port', str, ''), - Param('ssl', 'ssl', _str_to_bool, True), - Param('imap', 'imap', _str_to_bool, True), - Param('idle', 'idle', _str_to_bool, True), - Param('folders', 'folder', _str_to_folders, []), + Param('user', 'user', str, str, ''), + Param('password', 'password', str, str, ''), + Param('server', 'server', str, str, ''), + Param('port', 'port', str, str, ''), + Param('ssl', 'ssl', _str_to_bool, _bool_to_str, True), + Param('imap', 'imap', _str_to_bool, _bool_to_str, True), + Param('idle', 'idle', _str_to_bool, _bool_to_str, True), + Param('folders', 'folder', _str_to_folders, _folders_to_str, []), ]), 'pop3' : Backend(POP3MailboxBackend, [ - Param('user', 'user', str, ''), - Param('password', 'password', str, ''), - Param('server', 'server', str, ''), - Param('port', 'port', str, ''), - Param('ssl', 'ssl', _str_to_bool, True), - Param('imap', 'imap', _str_to_bool, False), - Param('idle', 'idle', _str_to_bool, False), + Param('user', 'user', str, str, ''), + Param('password', 'password', str, str, ''), + Param('server', 'server', str, str, ''), + Param('port', 'port', str, str, ''), + Param('ssl', 'ssl', _str_to_bool, _bool_to_str, True), + Param('imap', 'imap', _str_to_bool, _bool_to_str, False), + Param('idle', 'idle', _str_to_bool, _bool_to_str, False), ]), } diff --git a/Mailnag/common/accounts.py b/Mailnag/common/accounts.py index c2c99d9..9c4c10e 100644 --- a/Mailnag/common/accounts.py +++ b/Mailnag/common/accounts.py @@ -25,7 +25,6 @@ # import logging -import json from Mailnag.backends import create_backend, get_mailbox_parameter_specs account_defaults = { @@ -49,7 +48,7 @@ CREDENTIAL_KEY = 'Mailnag password for %s://%s@%s' # class Account: def __init__(self, enabled = False, name = '', user = '', \ - password = '', oauth2string = '', server = '', port = '', ssl = True, imap = True, idle = True, folders = [], backend = None, mailbox_type = None): + password = '', oauth2string = '', server = '', port = '', ssl = True, imap = True, idle = True, folders = [], backend = None, mailbox_type = None, **kw): self.enabled = enabled # bool if mailbox_type: @@ -67,6 +66,27 @@ class Account: self.idle = idle # bool self.folders = folders self.backend = backend + self._rest_of_config = kw + + + def get_config(self): + """Return account's configuration as a dict.""" + config = { + 'enabled': self.enabled, + 'mailbox_type': self.mailbox_type, + 'name': self.name, + 'user': self.user, + 'password': self.password, + 'oauth2string': self.oauth2string, + 'server': self.server, + 'port': self.port, + 'ssl': self.ssl, + 'imap': self.imap, + 'idle': self.idle, + 'folders': self.folders, + } + config.update(self._rest_of_config) + return config def open(self): @@ -240,20 +260,18 @@ class AccountManager: cfg.set(section_name, 'enabled', int(acc.enabled)) cfg.set(section_name, 'type', acc.mailbox_type) cfg.set(section_name, 'name', acc.name) - cfg.set(section_name, 'user', acc.user) - cfg.set(section_name, 'password', '') - cfg.set(section_name, 'server', acc.server) - cfg.set(section_name, 'port', acc.port) - cfg.set(section_name, 'ssl', int(acc.ssl)) - cfg.set(section_name, 'imap', int(acc.imap)) - cfg.set(section_name, 'idle', int(acc.idle)) - cfg.set(section_name, 'folder', json.dumps(acc.folders)) - + + config = acc.get_config() + option_spec = get_mailbox_parameter_specs(acc.mailbox_type) + + # TODO: Setting password to credentials is mailbox specific. + # Every backend do not have or need password. if self._credentialstore != None: protocol = 'imap' if acc.imap else 'pop' self._credentialstore.set(CREDENTIAL_KEY % (protocol, acc.user, acc.server), acc.password) - else: - cfg.set(section_name, 'password', acc.password) + config['password'] = '' + + self._set_cfg_options(cfg, section_name, config, option_spec) i = i + 1 @@ -283,3 +301,12 @@ class AccountManager: value = default_value return value + + def _set_cfg_options(self, cfg, section_name, options, option_spec): + for s in option_spec: + if s.to_str and s.param_name in options: + value = s.to_str(options[s.param_name]) + else: + value = s.default_value + cfg.set(section_name, s.option_name, value) + diff --git a/tests/test_account.py b/tests/test_account.py new file mode 100644 index 0000000..cd0c6c9 --- /dev/null +++ b/tests/test_account.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# +# test_account.py +# +# Copyright 2016 Timo Kankare +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +"""Test cases for Account.""" + +from Mailnag.common.accounts import Account + + +def test_account_should_keep_configuration(): + account = Account(enabled=True, + name='my name', + user='who', + password='secret', + oauth2string='who knows', + server='example.org', + port='1234', + ssl=True, + imap=True, + idle=True, + folders=['a', 'b'], + mailbox_type='mybox') + config = account.get_config() + expected_config = { + 'enabled': True, + 'name': 'my name', + 'user': 'who', + 'password': 'secret', + 'oauth2string': 'who knows', + 'server': 'example.org', + 'port': '1234', + 'ssl': True, + 'imap': True, + 'idle': True, + 'folders': ['a', 'b'], + 'mailbox_type': 'mybox', + } + assert expected_config == config + + +def test_account_config_should_always_contain_certain_values(): + account = Account() + config = account.get_config() + assert 'enabled' in config + assert 'name' in config + assert 'mailbox_type' in config + + +def test_account_should_configurable_with_any_parameters(): + account = Account(weird='odd', odd='weird') + config = account.get_config() + assert config['weird'] == 'odd' + assert config['odd'] == 'weird' + diff --git a/tests/test_accountmanager.py b/tests/test_accountmanager.py index 5db3d51..657c693 100644 --- a/tests/test_accountmanager.py +++ b/tests/test_accountmanager.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# test_backends.py +# test_accountmanager.py # # Copyright 2016 Timo Kankare # @@ -168,3 +168,32 @@ def test_pop3_config_defaults(config): } assert expected_options == options + +def test_imap_config_values_should_be_stored(): + am = AccountManager() + option_spec = get_mailbox_parameter_specs('imap') + options = { + 'user': 'you', + 'password': '', + 'server': 'imap.example.org', + 'port': '', + 'ssl': True, + 'imap': True, + 'idle': True, + 'folders': ['a', 'b'], + } + config = RawConfigParser() + config.add_section('account1') + am._set_cfg_options(config, 'account1', options, option_spec) + expected_config_items = [ + ('user', 'you'), + ('password', ''), + ('server', 'imap.example.org'), + ('port', ''), + ('ssl', '1'), + ('imap', '1'), + ('idle', '1'), + ('folder', '["a", "b"]'), + ] + assert set(expected_config_items) == set(config.items('account1')) +