mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-20 10:34:30 +00:00
ejabberd: Add multi-select form for domains
Choices includes all of the available domain names in the system, as well as any domains that are in ejabberd configuration. Tests: - Disable a domain. It is removed from ejabberd config. - Enable a domain. It is added to ejabberd config. - Enable all name services. Run ejabberd functional tests and observe that they pass. Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
parent
7d4c3dbb67
commit
1a39212313
@ -70,11 +70,19 @@ def parse_arguments():
|
|||||||
hostname_change.add_argument('--old-hostname', help='Previous hostname')
|
hostname_change.add_argument('--old-hostname', help='Previous hostname')
|
||||||
hostname_change.add_argument('--new-hostname', help='New hostname')
|
hostname_change.add_argument('--new-hostname', help='New hostname')
|
||||||
|
|
||||||
# Add a domain name to ejabberd
|
# Manage domain names
|
||||||
|
subparsers.add_parser('get-domains',
|
||||||
|
help='Get all configured domains in JSON format')
|
||||||
|
|
||||||
add_domain = subparsers.add_parser('add-domain',
|
add_domain = subparsers.add_parser('add-domain',
|
||||||
help='Add a domain name to ejabberd')
|
help='Add a domain name to ejabberd')
|
||||||
add_domain.add_argument('--domainname', help='New domain name')
|
add_domain.add_argument('--domainname', help='New domain name')
|
||||||
|
|
||||||
|
set_domains = subparsers.add_parser('set-domains',
|
||||||
|
help='Set list of ejabberd domains')
|
||||||
|
set_domains.add_argument('--domains', nargs='+',
|
||||||
|
help='One or more domain names')
|
||||||
|
|
||||||
# Configure STUN/TURN server for use with ejabberd
|
# Configure STUN/TURN server for use with ejabberd
|
||||||
turn = subparsers.add_parser(
|
turn = subparsers.add_parser(
|
||||||
'configure-turn', help='Configure a TURN server for use with ejabberd')
|
'configure-turn', help='Configure a TURN server for use with ejabberd')
|
||||||
@ -236,8 +244,23 @@ def subcommand_change_hostname(arguments):
|
|||||||
EJABBERD_BACKUP_NEW)
|
EJABBERD_BACKUP_NEW)
|
||||||
|
|
||||||
|
|
||||||
|
def subcommand_get_domains(_):
|
||||||
|
"""Get all configured domains."""
|
||||||
|
if not shutil.which('ejabberdctl'):
|
||||||
|
print('ejabberdctl not found. Is ejabberd installed?')
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(EJABBERD_CONFIG, 'r') as file_handle:
|
||||||
|
conf = yaml.load(file_handle)
|
||||||
|
|
||||||
|
print(json.dumps(conf['hosts']))
|
||||||
|
|
||||||
|
|
||||||
def subcommand_add_domain(arguments):
|
def subcommand_add_domain(arguments):
|
||||||
"""Update ejabberd with new domainname"""
|
"""Update ejabberd with new domainname.
|
||||||
|
|
||||||
|
Restarting ejabberd is handled by letsencrypt-ejabberd component.
|
||||||
|
"""
|
||||||
if not shutil.which('ejabberdctl'):
|
if not shutil.which('ejabberdctl'):
|
||||||
print('ejabberdctl not found. Is ejabberd installed?')
|
print('ejabberdctl not found. Is ejabberd installed?')
|
||||||
return
|
return
|
||||||
@ -255,6 +278,26 @@ def subcommand_add_domain(arguments):
|
|||||||
with open(EJABBERD_CONFIG, 'w') as file_handle:
|
with open(EJABBERD_CONFIG, 'w') as file_handle:
|
||||||
yaml.dump(conf, file_handle)
|
yaml.dump(conf, file_handle)
|
||||||
|
|
||||||
|
# Restarting ejabberd is handled by letsencrypt-ejabberd component.
|
||||||
|
|
||||||
|
|
||||||
|
def subcommand_set_domains(arguments):
|
||||||
|
"""Set list of ejabberd domains.
|
||||||
|
|
||||||
|
Restarting ejabberd is handled by letsencrypt-ejabberd component.
|
||||||
|
"""
|
||||||
|
if not shutil.which('ejabberdctl'):
|
||||||
|
print('ejabberdctl not found. Is ejabberd installed?')
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(EJABBERD_CONFIG, 'r') as file_handle:
|
||||||
|
conf = yaml.load(file_handle)
|
||||||
|
|
||||||
|
conf['hosts'] = arguments.domains
|
||||||
|
|
||||||
|
with open(EJABBERD_CONFIG, 'w') as file_handle:
|
||||||
|
yaml.dump(conf, file_handle)
|
||||||
|
|
||||||
|
|
||||||
def subcommand_mam(argument):
|
def subcommand_mam(argument):
|
||||||
"""Enable, disable, or get status of Message Archive Management (MAM)."""
|
"""Enable, disable, or get status of Message Archive Management (MAM)."""
|
||||||
|
|||||||
@ -158,22 +158,6 @@ def setup(helper, old_version=None):
|
|||||||
update_turn_configuration(configuration, force=True)
|
update_turn_configuration(configuration, force=True)
|
||||||
|
|
||||||
|
|
||||||
def get_domains():
|
|
||||||
"""Return the list of domains that ejabberd is interested in.
|
|
||||||
|
|
||||||
XXX: Retrieve the list from ejabberd configuration.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if app.needs_setup():
|
|
||||||
return []
|
|
||||||
|
|
||||||
domain_name = config.get_domainname()
|
|
||||||
if domain_name:
|
|
||||||
return [domain_name]
|
|
||||||
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs):
|
def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs):
|
||||||
"""
|
"""
|
||||||
Backup ejabberd database before hostname is changed.
|
Backup ejabberd database before hostname is changed.
|
||||||
@ -202,19 +186,39 @@ def on_post_hostname_change(sender, old_hostname, new_hostname, **kwargs):
|
|||||||
], run_in_background=True)
|
], run_in_background=True)
|
||||||
|
|
||||||
|
|
||||||
|
def get_domains():
|
||||||
|
"""Return the list of domains configured for ejabberd.
|
||||||
|
"""
|
||||||
|
if app.needs_setup():
|
||||||
|
return []
|
||||||
|
|
||||||
|
output = actions.superuser_run('ejabberd', ['get-domains'])
|
||||||
|
return json.loads(output)
|
||||||
|
|
||||||
|
|
||||||
def on_domain_added(sender, domain_type, name='', description='',
|
def on_domain_added(sender, domain_type, name='', description='',
|
||||||
services=None, **kwargs):
|
services=None, **kwargs):
|
||||||
"""Update ejabberd config after domain name change."""
|
"""Update ejabberd config after domain name change."""
|
||||||
if not name or app.needs_setup():
|
if not name or app.needs_setup():
|
||||||
return
|
return
|
||||||
|
|
||||||
conf = actions.superuser_run('ejabberd', ['get-configuration'])
|
domains = get_domains()
|
||||||
conf = json.loads(conf)
|
if name not in domains:
|
||||||
if name not in conf['domains']:
|
|
||||||
actions.superuser_run('ejabberd', ['add-domain', '--domainname', name])
|
actions.superuser_run('ejabberd', ['add-domain', '--domainname', name])
|
||||||
app.get_component('letsencrypt-ejabberd').setup_certificates()
|
app.get_component('letsencrypt-ejabberd').setup_certificates()
|
||||||
|
|
||||||
|
|
||||||
|
def set_domains(domains):
|
||||||
|
"""Configure ejabberd to have this list of domains."""
|
||||||
|
if not domains or app.needs_setup():
|
||||||
|
return
|
||||||
|
|
||||||
|
commands = ['set-domains', '--domains']
|
||||||
|
commands.extend(domains)
|
||||||
|
actions.superuser_run('ejabberd', commands)
|
||||||
|
app.get_component('letsencrypt-ejabberd').setup_certificates()
|
||||||
|
|
||||||
|
|
||||||
def update_turn_configuration(config: TurnConfiguration, managed=True,
|
def update_turn_configuration(config: TurnConfiguration, managed=True,
|
||||||
force=False):
|
force=False):
|
||||||
"""Update ejabberd's STUN/TURN server configuration."""
|
"""Update ejabberd's STUN/TURN server configuration."""
|
||||||
|
|||||||
@ -8,12 +8,21 @@ from django.urls import reverse_lazy
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from plinth import cfg
|
from plinth import cfg
|
||||||
|
from plinth.modules import ejabberd
|
||||||
from plinth.modules.coturn.forms import turn_uris_validator
|
from plinth.modules.coturn.forms import turn_uris_validator
|
||||||
from plinth.utils import format_lazy
|
from plinth.utils import format_lazy
|
||||||
|
|
||||||
|
|
||||||
class EjabberdForm(forms.Form):
|
class EjabberdForm(forms.Form):
|
||||||
"""Ejabberd configuration form."""
|
"""Ejabberd configuration form."""
|
||||||
|
domain_names = forms.MultipleChoiceField(
|
||||||
|
label=_('Domain names'), widget=forms.CheckboxSelectMultiple,
|
||||||
|
help_text=_(
|
||||||
|
'Domains to be used by ejabberd. "localhost" is always included, '
|
||||||
|
'so it is not shown here. Note that user accounts are unique for '
|
||||||
|
'each domain, and migrating users to a new domain name is not yet '
|
||||||
|
'implemented.'), choices=[])
|
||||||
|
|
||||||
MAM_enabled = forms.BooleanField(
|
MAM_enabled = forms.BooleanField(
|
||||||
label=_('Enable Message Archive Management'), required=False,
|
label=_('Enable Message Archive Management'), required=False,
|
||||||
help_text=format_lazy(
|
help_text=format_lazy(
|
||||||
@ -43,6 +52,18 @@ class EjabberdForm(forms.Form):
|
|||||||
help_text=_('Shared secret used to compute passwords for the '
|
help_text=_('Shared secret used to compute passwords for the '
|
||||||
'TURN server.'))
|
'TURN server.'))
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Start with any existing domains from ejabberd configuration.
|
||||||
|
domains = set(ejabberd.get_domains())
|
||||||
|
|
||||||
|
# Add other domains that can be configured.
|
||||||
|
from plinth.modules.names.components import DomainName
|
||||||
|
domains |= DomainName.list_names()
|
||||||
|
|
||||||
|
self.fields['domain_names'].choices = zip(domains, domains)
|
||||||
|
|
||||||
def clean_turn_uris(self):
|
def clean_turn_uris(self):
|
||||||
"""Normalize newlines in URIs."""
|
"""Normalize newlines in URIs."""
|
||||||
data = self.cleaned_data['turn_uris']
|
data = self.cleaned_data['turn_uris']
|
||||||
|
|||||||
@ -8,8 +8,7 @@ from plinth.tests import functional
|
|||||||
|
|
||||||
pytestmark = [pytest.mark.apps, pytest.mark.ejabberd]
|
pytestmark = [pytest.mark.apps, pytest.mark.ejabberd]
|
||||||
|
|
||||||
# TODO Check service
|
# TODO Check domain name displayed in description
|
||||||
# TODO Check domain name display
|
|
||||||
|
|
||||||
|
|
||||||
class TestEjabberdApp(functional.BaseAppTests):
|
class TestEjabberdApp(functional.BaseAppTests):
|
||||||
@ -17,6 +16,29 @@ class TestEjabberdApp(functional.BaseAppTests):
|
|||||||
has_service = True
|
has_service = True
|
||||||
has_web = False
|
has_web = False
|
||||||
|
|
||||||
|
@pytest.fixture(scope='module', autouse=True)
|
||||||
|
def fixture_background(self, session_browser):
|
||||||
|
"""Login, install, and enable the app."""
|
||||||
|
functional.login(session_browser)
|
||||||
|
functional.install(session_browser, self.app_name)
|
||||||
|
functional.app_enable(session_browser, self.app_name)
|
||||||
|
yield
|
||||||
|
functional.login(session_browser)
|
||||||
|
functional.app_disable(session_browser, self.app_name)
|
||||||
|
|
||||||
|
def test_add_remove_domain(self, session_browser):
|
||||||
|
"""Test adding and removing a domain."""
|
||||||
|
functional.app_enable(session_browser, 'ejabberd')
|
||||||
|
_enable_domain(session_browser, 'freedombox.local')
|
||||||
|
|
||||||
|
_disable_domain(session_browser, 'freedombox.local')
|
||||||
|
assert not _is_domain_enabled(session_browser, 'freedombox.local')
|
||||||
|
assert functional.service_is_running(session_browser, 'ejabberd')
|
||||||
|
|
||||||
|
_enable_domain(session_browser, 'freedombox.local')
|
||||||
|
assert _is_domain_enabled(session_browser, 'freedombox.local')
|
||||||
|
assert functional.service_is_running(session_browser, 'ejabberd')
|
||||||
|
|
||||||
def test_message_archive_management(self, session_browser):
|
def test_message_archive_management(self, session_browser):
|
||||||
"""Test enabling message archive management."""
|
"""Test enabling message archive management."""
|
||||||
functional.app_enable(session_browser, 'ejabberd')
|
functional.app_enable(session_browser, 'ejabberd')
|
||||||
@ -39,6 +61,29 @@ class TestEjabberdApp(functional.BaseAppTests):
|
|||||||
_jsxc_assert_has_contact(session_browser)
|
_jsxc_assert_has_contact(session_browser)
|
||||||
|
|
||||||
|
|
||||||
|
def _enable_domain(browser, domain):
|
||||||
|
"""Add domain name to Ejabberd configuration."""
|
||||||
|
functional.nav_to_module(browser, 'ejabberd')
|
||||||
|
checkbox = browser.find_by_value(domain).first
|
||||||
|
checkbox.check()
|
||||||
|
functional.submit(browser, form_class='form-configuration')
|
||||||
|
|
||||||
|
|
||||||
|
def _disable_domain(browser, domain):
|
||||||
|
"""Remove domain name from Ejabberd configuration."""
|
||||||
|
functional.nav_to_module(browser, 'ejabberd')
|
||||||
|
checkbox = browser.find_by_value(domain).first
|
||||||
|
checkbox.uncheck()
|
||||||
|
functional.submit(browser, form_class='form-configuration')
|
||||||
|
|
||||||
|
|
||||||
|
def _is_domain_enabled(browser, domain):
|
||||||
|
"""Return whether the domain name is enabled."""
|
||||||
|
functional.nav_to_module(browser, 'ejabberd')
|
||||||
|
checkbox = browser.find_by_value(domain).first
|
||||||
|
return checkbox.checked
|
||||||
|
|
||||||
|
|
||||||
def _enable_message_archive_management(browser):
|
def _enable_message_archive_management(browser):
|
||||||
"""Enable Message Archive Management in Ejabberd."""
|
"""Enable Message Archive Management in Ejabberd."""
|
||||||
functional.nav_to_module(browser, 'ejabberd')
|
functional.nav_to_module(browser, 'ejabberd')
|
||||||
|
|||||||
@ -24,6 +24,7 @@ class EjabberdAppView(AppView):
|
|||||||
"""Initial data to fill in the form."""
|
"""Initial data to fill in the form."""
|
||||||
config, managed = ejabberd.get_turn_configuration()
|
config, managed = ejabberd.get_turn_configuration()
|
||||||
return super().get_initial() | {
|
return super().get_initial() | {
|
||||||
|
'domain_names': ejabberd.get_domains(),
|
||||||
'MAM_enabled': self.is_MAM_enabled(),
|
'MAM_enabled': self.is_MAM_enabled(),
|
||||||
'enable_managed_turn': managed,
|
'enable_managed_turn': managed,
|
||||||
'turn_uris': '\n'.join(config.uris),
|
'turn_uris': '\n'.join(config.uris),
|
||||||
@ -37,6 +38,11 @@ class EjabberdAppView(AppView):
|
|||||||
context['domainname'] = domains[0] if domains else None
|
context['domainname'] = domains[0] if domains else None
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _handle_domain_names_configuration(new_config):
|
||||||
|
"""Update list of domain names in configuration."""
|
||||||
|
ejabberd.set_domains(new_config['domain_names'])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _handle_turn_configuration(old_config, new_config):
|
def _handle_turn_configuration(old_config, new_config):
|
||||||
if not new_config['enable_managed_turn']:
|
if not new_config['enable_managed_turn']:
|
||||||
@ -72,6 +78,11 @@ class EjabberdAppView(AppView):
|
|||||||
return old_config[prop] != new_config[prop]
|
return old_config[prop] != new_config[prop]
|
||||||
|
|
||||||
is_changed = False
|
is_changed = False
|
||||||
|
|
||||||
|
if changed('domain_names'):
|
||||||
|
self._handle_domain_names_configuration(new_config)
|
||||||
|
is_changed = True
|
||||||
|
|
||||||
if changed('MAM_enabled'):
|
if changed('MAM_enabled'):
|
||||||
self._handle_MAM_configuration(old_config, new_config)
|
self._handle_MAM_configuration(old_config, new_config)
|
||||||
is_changed = True
|
is_changed = True
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user