fix formatting issues

Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Alice Kile 2019-11-04 15:57:38 +05:30 committed by James Valleroy
parent fa74a26042
commit eb83e00011
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
134 changed files with 598 additions and 720 deletions

View File

@ -109,8 +109,9 @@ def subcommand_generate_ticket(arguments):
pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, fil.read().encode()) pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, fil.read().encode())
valid_until = minutes_from_now(12 * 60) valid_until = minutes_from_now(12 * 60)
grace_period = minutes_from_now(11 * 60) grace_period = minutes_from_now(11 * 60)
print(create_ticket(pkey, uid, valid_until, tokens=tokens, print(
graceperiod=grace_period)) create_ticket(pkey, uid, valid_until, tokens=tokens,
graceperiod=grace_period))
def minutes_from_now(minutes): def minutes_from_now(minutes):
@ -120,8 +121,8 @@ def minutes_from_now(minutes):
def seconds_from_now(seconds): def seconds_from_now(seconds):
"""Return a timestamp at the given number of seconds from now.""" """Return a timestamp at the given number of seconds from now."""
return ( return (datetime.datetime.now() +
datetime.datetime.now() + datetime.timedelta(0, seconds)).timestamp() datetime.timedelta(0, seconds)).timestamp()
def main(): def main():

View File

@ -66,8 +66,8 @@ def subcommand_reset_home_page(_):
config_file = FREEDOMBOX_APACHE_CONFIG config_file = FREEDOMBOX_APACHE_CONFIG
default_path = 'plinth' default_path = 'plinth'
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') aug.set('/augeas/load/Httpd/lens', 'Httpd.lns')
aug.set('/augeas/load/Httpd/incl[last() + 1]', config_file) aug.set('/augeas/load/Httpd/incl[last() + 1]', config_file)
aug.load() aug.load()

View File

@ -72,8 +72,8 @@ def set_domain_name(domain_name):
# {'url': domain_name}) # {'url': domain_name})
# Manually changing the domain name in the conf files. # Manually changing the domain name in the conf files.
conf_file = '/etc/diaspora.conf' conf_file = '/etc/diaspora.conf'
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
# lens for shell-script config file # lens for shell-script config file
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')

View File

@ -62,8 +62,9 @@ def parse_arguments():
# Add a service # Add a service
add_service = subparsers.add_parser('add-service', help='Add a service') add_service = subparsers.add_parser('add-service', help='Add a service')
add_service.add_argument('service', help='Name of the service to add') add_service.add_argument('service', help='Name of the service to add')
add_service.add_argument( add_service.add_argument('--zone',
'--zone', help='Zone to which service is to be added', required=True) help='Zone to which service is to be added',
required=True)
# Remove a service status # Remove a service status
remove_service = subparsers.add_parser('remove-service', remove_service = subparsers.add_parser('remove-service',
@ -111,8 +112,8 @@ def _flush_iptables_rules():
def set_firewall_backend(backend): def set_firewall_backend(backend):
"""Set FirewallBackend attribute to the specified string.""" """Set FirewallBackend attribute to the specified string."""
conf_file = '/etc/firewalld/firewalld.conf' conf_file = '/etc/firewalld/firewalld.conf'
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
# lens for shell-script config file # lens for shell-script config file
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')

View File

@ -38,7 +38,6 @@ logger = logging.getLogger(__name__)
class ValidateRepoName(argparse.Action): class ValidateRepoName(argparse.Action):
"""Validate a repository name and add .git extension if necessary.""" """Validate a repository name and add .git extension if necessary."""
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
RepositoryValidator()(values) RepositoryValidator()(values)
if not values.endswith('.git'): if not values.endswith('.git'):
@ -48,7 +47,6 @@ class ValidateRepoName(argparse.Action):
class ValidateRepoUrl(argparse.Action): class ValidateRepoUrl(argparse.Action):
"""Validate a repository URL.""" """Validate a repository URL."""
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
RepositoryValidator(input_should_be='url')(values) RepositoryValidator(input_should_be='url')(values)
setattr(namespace, self.dest, values) setattr(namespace, self.dest, values)
@ -359,8 +357,9 @@ def subcommand_repo_info(arguments):
print( print(
json.dumps( json.dumps(
dict(name=arguments.name[:-4], description=_get_repo_description( dict(name=arguments.name[:-4],
arguments.name), owner=_get_repo_owner(arguments.name), description=_get_repo_description(arguments.name),
owner=_get_repo_owner(arguments.name),
access=_get_access_status(arguments.name)))) access=_get_access_status(arguments.name))))

View File

@ -48,8 +48,8 @@ def parse_arguments():
help_private_mode = 'Enable/Disable/Status private mode.' help_private_mode = 'Enable/Disable/Status private mode.'
private_mode = subparsers.add_parser('private-mode', private_mode = subparsers.add_parser('private-mode',
help=help_private_mode) help=help_private_mode)
private_mode.add_argument('command', choices=('enable', 'disable', private_mode.add_argument('command',
'status'), choices=('enable', 'disable', 'status'),
help=help_private_mode) help=help_private_mode)
change_password = subparsers.add_parser('change-password', change_password = subparsers.add_parser('change-password',

View File

@ -15,7 +15,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Configuration helper for Minetest server. Configuration helper for Minetest server.
""" """
@ -25,7 +24,6 @@ import augeas
from plinth import action_utils from plinth import action_utils
CONFIG_FILE = '/etc/minetest/minetest.conf' CONFIG_FILE = '/etc/minetest/minetest.conf'
AUG_PATH = '/files' + CONFIG_FILE + '/.anon' AUG_PATH = '/files' + CONFIG_FILE + '/.anon'

View File

@ -150,9 +150,8 @@ def get_monkeysphere_keys(key_id=None):
"""Return the list of keys imported into monkeysphere.""" """Return the list of keys imported into monkeysphere."""
try: try:
key_ids = [] if not key_id else [key_id] key_ids = [] if not key_id else [key_id]
output = subprocess.check_output( output = subprocess.check_output(['monkeysphere-host', 'show-keys'] +
['monkeysphere-host', 'show-keys'] + key_ids, key_ids, stderr=subprocess.DEVNULL)
stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
# no keys available # no keys available
return {} return {}
@ -288,9 +287,10 @@ def subcommand_host_publish_key(arguments):
# setting TMPDIR as workaround for Debian bug #656750 # setting TMPDIR as workaround for Debian bug #656750
proc = subprocess.Popen( proc = subprocess.Popen(
['monkeysphere-host', 'publish-keys'] + arguments.key_ids, ['monkeysphere-host', 'publish-keys'] + arguments.key_ids,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=dict( stdout=subprocess.PIPE, stderr=subprocess.PIPE,
os.environ, TMPDIR='/var/lib/monkeysphere/authentication/tmp/', env=dict(os.environ,
MONKEYSPHERE_PROMPT='false')) TMPDIR='/var/lib/monkeysphere/authentication/tmp/',
MONKEYSPHERE_PROMPT='false'))
output, error = proc.communicate() output, error = proc.communicate()
output, error = output.decode(), error.decode() output, error = output.decode(), error.decode()
if proc.returncode != 0: if proc.returncode != 0:

View File

@ -177,8 +177,8 @@ def subcommand_upgrade(_):
'renewed/private_by_serial', 'renewed/reqs_by_serial' 'renewed/private_by_serial', 'renewed/reqs_by_serial'
] ]
for dir_name in directories_to_create: for dir_name in directories_to_create:
os.makedirs( os.makedirs(os.path.join(pki_dir, dir_name), mode=0o700,
os.path.join(pki_dir, dir_name), mode=0o700, exist_ok=True) exist_ok=True)
def _move_by_file_extension(file_extension, directory, excluded=None): def _move_by_file_extension(file_extension, directory, excluded=None):
excluded = excluded or [] excluded = excluded or []
@ -217,7 +217,6 @@ def _write_server_config():
def _setup_firewall(): def _setup_firewall():
"""Add TUN device to internal zone in firewalld.""" """Add TUN device to internal zone in firewalld."""
def _configure_interface(interface, operation): def _configure_interface(interface, operation):
"""Add or remove an interface into internal zone.""" """Add or remove an interface into internal zone."""
command = [ command = [
@ -299,9 +298,10 @@ def subcommand_get_profile(arguments):
user_key_string = _read_file(user_key) user_key_string = _read_file(user_key)
ca_string = _read_file(CA_CERTIFICATE_PATH) ca_string = _read_file(CA_CERTIFICATE_PATH)
profile = CLIENT_CONFIGURATION.format( profile = CLIENT_CONFIGURATION.format(ca=ca_string,
ca=ca_string, cert=user_certificate_string, key=user_key_string, cert=user_certificate_string,
remote=remote_server) key=user_key_string,
remote=remote_server)
print(profile) print(profile)
@ -326,8 +326,8 @@ def _is_non_empty_file(filepath):
def load_augeas(): def load_augeas():
"""Initialize Augeas.""" """Initialize Augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
# shell-script config file lens # shell-script config file lens
aug.set('/augeas/load/Simplevars/lens', 'Simplevars.lns') aug.set('/augeas/load/Simplevars/lens', 'Simplevars.lns')

View File

@ -349,8 +349,9 @@ def _download_packages(packages):
return downloaded_files return downloaded_files
def _get_conffile_hashes_from_downloaded_files( def _get_conffile_hashes_from_downloaded_files(packages, downloaded_files,
packages, downloaded_files, status_hashes, mismatched_hashes): status_hashes,
mismatched_hashes):
"""Retrieve the conffile hashes from downloaded .deb files.""" """Retrieve the conffile hashes from downloaded .deb files."""
new_hashes = defaultdict(dict) new_hashes = defaultdict(dict)
new_versions = defaultdict(lambda: None) new_versions = defaultdict(lambda: None)
@ -369,8 +370,9 @@ def _get_conffile_hashes_from_downloaded_files(
return new_hashes, new_versions return new_hashes, new_versions
def _get_conffile_hashes_from_downloaded_file( def _get_conffile_hashes_from_downloaded_file(packages, downloaded_file,
packages, downloaded_file, status_hashes, mismatched_hashes): status_hashes,
mismatched_hashes):
"""Retrieve the conffile hashes from a single downloaded .deb file.""" """Retrieve the conffile hashes from a single downloaded .deb file."""
deb_file = apt_inst.DebFile(downloaded_file) deb_file = apt_inst.DebFile(downloaded_file)

View File

@ -31,13 +31,18 @@ from plinth.modules.pagekite import utils
aug = None aug = None
PATHS = { PATHS = {
'service_on': os.path.join(utils.CONF_PATH, '*', 'service_on', '*'), 'service_on':
'kitename': os.path.join(utils.CONF_PATH, '10_account.rc', 'kitename'), os.path.join(utils.CONF_PATH, '*', 'service_on', '*'),
'kitesecret': os.path.join(utils.CONF_PATH, '10_account.rc', 'kitesecret'), 'kitename':
'abort_not_configured': os.path.join(utils.CONF_PATH, '10_account.rc', os.path.join(utils.CONF_PATH, '10_account.rc', 'kitename'),
'abort_not_configured'), 'kitesecret':
'defaults': os.path.join(utils.CONF_PATH, '20_frontends.rc', 'defaults'), os.path.join(utils.CONF_PATH, '10_account.rc', 'kitesecret'),
'frontend': os.path.join(utils.CONF_PATH, '20_frontends.rc', 'frontend'), 'abort_not_configured':
os.path.join(utils.CONF_PATH, '10_account.rc', 'abort_not_configured'),
'defaults':
os.path.join(utils.CONF_PATH, '20_frontends.rc', 'defaults'),
'frontend':
os.path.join(utils.CONF_PATH, '20_frontends.rc', 'frontend'),
} }
@ -50,9 +55,9 @@ def parse_arguments():
subparsers.add_parser('start-and-enable', help='Enable PageKite service') subparsers.add_parser('start-and-enable', help='Enable PageKite service')
subparsers.add_parser('stop-and-disable', help='Disable PageKite service') subparsers.add_parser('stop-and-disable', help='Disable PageKite service')
subparsers.add_parser('restart', help='Restart PageKite service') subparsers.add_parser('restart', help='Restart PageKite service')
subparsers.add_parser('is-disabled', subparsers.add_parser(
help=('Whether PageKite is disabled in the file ' 'is-disabled', help=('Whether PageKite is disabled in the file '
'/etc/pagekite.d/10_accounts.rc')) '/etc/pagekite.d/10_accounts.rc'))
# Frontend # Frontend
subparsers.add_parser('get-frontend', help='Get pagekite frontend') subparsers.add_parser('get-frontend', help='Get pagekite frontend')

View File

@ -15,7 +15,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Configuration helper for power controls. Configuration helper for power controls.
""" """

View File

@ -132,8 +132,8 @@ def subcommand_fix_collections(_):
def load_augeas(): def load_augeas():
"""Initialize Augeas.""" """Initialize Augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
# shell-script config file lens # shell-script config file lens
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')

View File

@ -81,8 +81,8 @@ def _update_uwsgi_configuration():
uwsgi 2.0.15-debian crashes when trying to autoload. uwsgi 2.0.15-debian crashes when trying to autoload.
""" """
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/inifile/lens', 'Puppet.lns') aug.set('/augeas/load/inifile/lens', 'Puppet.lns')
aug.set('/augeas/load/inifile/incl[last() + 1]', UWSGI_FILE) aug.set('/augeas/load/inifile/incl[last() + 1]', UWSGI_FILE)
aug.load() aug.load()

View File

@ -35,12 +35,11 @@ def parse_arguments():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
subparsers.add_parser('setup', subparsers.add_parser('setup', help='Perform initial setup steps')
help='Perform initial setup steps') subparsers.add_parser('get-config',
subparsers.add_parser( help='Read and print JSON config to stdout')
'get-config', help='Read and print JSON config to stdout') subparsers.add_parser('merge-config',
subparsers.add_parser( help='Merge JSON config from stdin with existing')
'merge-config', help='Merge JSON config from stdin with existing')
subparsers.required = True subparsers.required = True
return parser.parse_args() return parser.parse_args()

View File

@ -58,8 +58,8 @@ def parse_arguments():
def load_augeas(): def load_augeas():
"""Initialize augeas for this app's configuration file.""" """Initialize augeas for this app's configuration file."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') aug.set('/augeas/load/Httpd/lens', 'Httpd.lns')
aug.set('/augeas/load/Httpd/incl[last() + 1]', APACHE_CONFIGURATION) aug.set('/augeas/load/Httpd/incl[last() + 1]', APACHE_CONFIGURATION)
aug.load() aug.load()
@ -191,8 +191,9 @@ def _list(aug=None):
"""Must contain the line 'Require all granted'.""" """Must contain the line 'Require all granted'."""
require = location + '//directive["Require"]' require = location + '//directive["Require"]'
return bool(aug.match(require)) and aug.get( return bool(aug.match(require)) and aug.get(
require + '/arg[1]') == 'all' and aug.get( require +
require + '/arg[2]') == 'granted' '/arg[1]') == 'all' and aug.get(require +
'/arg[2]') == 'granted'
for share in shares: for share in shares:
if share['name'] == name: if share['name'] == name:

View File

@ -117,8 +117,8 @@ def subcommand_set_keys(arguments):
def _load_augeas(): def _load_augeas():
"""Initialize augeas for this app's configuration file.""" """Initialize augeas for this app's configuration file."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Sshd/lens', 'Sshd.lns') aug.set('/augeas/load/Sshd/lens', 'Sshd.lns')
aug.set('/augeas/load/Sshd/incl[last() + 1]', '/etc/ssh/sshd_config') aug.set('/augeas/load/Sshd/incl[last() + 1]', '/etc/ssh/sshd_config')
aug.load() aug.load()

View File

@ -96,11 +96,11 @@ def validate_mountpoint(mountpoint):
"""Check that the folder is empty, and create it if it doesn't exist""" """Check that the folder is empty, and create it if it doesn't exist"""
if os.path.exists(mountpoint): if os.path.exists(mountpoint):
if _is_mounted(mountpoint): if _is_mounted(mountpoint):
raise AlreadyMountedError( raise AlreadyMountedError('Mountpoint %s already mounted' %
'Mountpoint %s already mounted' % mountpoint) mountpoint)
if os.listdir(mountpoint) or not os.path.isdir(mountpoint): if os.listdir(mountpoint) or not os.path.isdir(mountpoint):
raise ValueError( raise ValueError('Mountpoint %s is not an empty directory' %
'Mountpoint %s is not an empty directory' % mountpoint) mountpoint)
else: else:
os.makedirs(mountpoint) os.makedirs(mountpoint)

View File

@ -114,8 +114,8 @@ def subcommand_setup(arguments):
def subcommand_autostart(_): def subcommand_autostart(_):
"""Automatically start all introducers and storage nodes on system startup. """Automatically start all introducers and storage nodes on system startup.
""" """
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
aug.set('/augeas/load/Shellvars/incl[last() + 1]', DEFAULT_FILE) aug.set('/augeas/load/Shellvars/incl[last() + 1]', DEFAULT_FILE)
aug.load() aug.load()
@ -157,8 +157,9 @@ def subcommand_create_storage_node(_):
if not os.path.exists(os.path.join(tahoe_home, storage_node_name)): if not os.path.exists(os.path.join(tahoe_home, storage_node_name)):
subprocess.check_call([ subprocess.check_call([
'tahoe', 'create-node', '--nickname=\"storage_node\"', 'tahoe', 'create-node', '--nickname=\"storage_node\"',
'--webport=1234', '--hostname={}'.format( '--webport=1234',
get_configured_domain_name()), storage_node_name '--hostname={}'.format(get_configured_domain_name()),
storage_node_name
]) ])
with open( with open(
os.path.join(tahoe_home, introducer_name, 'private', os.path.join(tahoe_home, introducer_name, 'private',

View File

@ -15,7 +15,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Set time zones with timedatectl (requires root permission). Set time zones with timedatectl (requires root permission).
""" """

View File

@ -529,8 +529,8 @@ def _update_ports():
def augeas_load(): def augeas_load():
"""Initialize Augeas.""" """Initialize Augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Tor/lens', 'Tor.lns') aug.set('/augeas/load/Tor/lens', 'Tor.lns')
aug.set('/augeas/load/Tor/incl[last() + 1]', aug.set('/augeas/load/Tor/incl[last() + 1]',
'/etc/tor/instances/plinth/torrc') '/etc/tor/instances/plinth/torrc')

View File

@ -133,8 +133,8 @@ def _run_as_postgres(command, stdin=None, stdout=None):
def load_augeas(): def load_augeas():
"""Initialize Augeas.""" """Initialize Augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
aug.set('/augeas/load/Shellvars/incl[last() + 1]', DEFAULT_FILE) aug.set('/augeas/load/Shellvars/incl[last() + 1]', DEFAULT_FILE)
aug.set('/augeas/load/Phpvars/lens', 'Phpvars.lns') aug.set('/augeas/load/Phpvars/lens', 'Phpvars.lns')

View File

@ -210,8 +210,8 @@ def configure_ldapscripts():
# modify a copy of the config file # modify a copy of the config file
shutil.copy('/etc/ldapscripts/ldapscripts.conf', LDAPSCRIPTS_CONF) shutil.copy('/etc/ldapscripts/ldapscripts.conf', LDAPSCRIPTS_CONF)
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
aug.set('/augeas/load/Shellvars/incl[last() + 1]', LDAPSCRIPTS_CONF) aug.set('/augeas/load/Shellvars/incl[last() + 1]', LDAPSCRIPTS_CONF)
aug.load() aug.load()

View File

@ -107,8 +107,7 @@ def select_domain_name(browser, app_name, domain_name):
@given('the shadowsocks application is configured') @given('the shadowsocks application is configured')
def configure_shadowsocks(browser): def configure_shadowsocks(browser):
application.configure_shadowsocks(browser, 'example.com', application.configure_shadowsocks(browser, 'example.com', 'fakepassword')
'fakepassword')
@when( @when(
@ -128,8 +127,8 @@ def assert_shadowsocks_configuration(browser, server, password):
password) == application.shadowsocks_get_configuration(browser) password) == application.shadowsocks_get_configuration(browser)
@when( @when(parsers.parse('I modify the maximum file size of coquelicot to {size:d}')
parsers.parse('I modify the maximum file size of coquelicot to {size:d}')) )
def modify_max_file_size(browser, size): def modify_max_file_size(browser, size):
application.modify_max_file_size(browser, size) application.modify_max_file_size(browser, size)
@ -372,38 +371,55 @@ def tahoe_given_add_introducer(browser, domain):
def tahoe_remove_introducer(browser, domain): def tahoe_remove_introducer(browser, domain):
application.tahoe_remove_introducer(browser, domain) application.tahoe_remove_introducer(browser, domain)
@given('the access rights are set to "only the owner can view or make changes"')
@given('the access rights are set to "only the owner can view or make changes"'
)
def radicale_given_owner_only(browser): def radicale_given_owner_only(browser):
application.radicale_set_access_rights(browser, 'owner_only') application.radicale_set_access_rights(browser, 'owner_only')
@given('the access rights are set to "any user can view, but only the owner can make changes"')
@given(
'the access rights are set to "any user can view, but only the owner can make changes"'
)
def radicale_given_owner_write(browser): def radicale_given_owner_write(browser):
application.radicale_set_access_rights(browser, 'owner_write') application.radicale_set_access_rights(browser, 'owner_write')
@given('the access rights are set to "any user can view or make changes"') @given('the access rights are set to "any user can view or make changes"')
def radicale_given_authenticated(browser): def radicale_given_authenticated(browser):
application.radicale_set_access_rights(browser, 'authenticated') application.radicale_set_access_rights(browser, 'authenticated')
@when('I change the access rights to "only the owner can view or make changes"')
@when('I change the access rights to "only the owner can view or make changes"'
)
def radicale_set_owner_only(browser): def radicale_set_owner_only(browser):
application.radicale_set_access_rights(browser, 'owner_only') application.radicale_set_access_rights(browser, 'owner_only')
@when('I change the access rights to "any user can view, but only the owner can make changes"')
@when(
'I change the access rights to "any user can view, but only the owner can make changes"'
)
def radicale_set_owner_write(browser): def radicale_set_owner_write(browser):
application.radicale_set_access_rights(browser, 'owner_write') application.radicale_set_access_rights(browser, 'owner_write')
@when('I change the access rights to "any user can view or make changes"') @when('I change the access rights to "any user can view or make changes"')
def radicale_set_authenticated(browser): def radicale_set_authenticated(browser):
application.radicale_set_access_rights(browser, 'authenticated') application.radicale_set_access_rights(browser, 'authenticated')
@then('the access rights should be "only the owner can view or make changes"') @then('the access rights should be "only the owner can view or make changes"')
def radicale_check_owner_only(browser): def radicale_check_owner_only(browser):
assert application.radicale_get_access_rights(browser) == 'owner_only' assert application.radicale_get_access_rights(browser) == 'owner_only'
@then('the access rights should be "any user can view, but only the owner can make changes"')
@then(
'the access rights should be "any user can view, but only the owner can make changes"'
)
def radicale_check_owner_write(browser): def radicale_check_owner_write(browser):
assert application.radicale_get_access_rights(browser) == 'owner_write' assert application.radicale_get_access_rights(browser) == 'owner_write'
@then('the access rights should be "any user can view or make changes"') @then('the access rights should be "any user can view or make changes"')
def radicale_check_authenticated(browser): def radicale_check_authenticated(browser):
assert application.radicale_get_access_rights(browser) == 'authenticated' assert application.radicale_get_access_rights(browser) == 'authenticated'
@ -451,8 +467,8 @@ def app_visible_on_front_page(browser, app_name):
assert len(shortcuts) == 1 assert len(shortcuts) == 1
@then( @then(parsers.parse('{app_name:w} app should not be visible on the front page')
parsers.parse('{app_name:w} app should not be visible on the front page')) )
def app_not_visible_on_front_page(browser, app_name): def app_not_visible_on_front_page(browser, app_name):
shortcuts = application.find_on_front_page(browser, app_name) shortcuts = application.find_on_front_page(browser, app_name)
assert len(shortcuts) == 0 assert len(shortcuts) == 0

View File

@ -19,7 +19,6 @@ from pytest_bdd import given, parsers, then, when
from support import config, interface from support import config, interface
default_url = config['DEFAULT']['url'] default_url = config['DEFAULT']['url']
@ -52,8 +51,8 @@ def new_user_does_not_exist(browser, name):
@given(parsers.parse('the user {name:w} exists')) @given(parsers.parse('the user {name:w} exists'))
def test_user_exists(browser, name): def test_user_exists(browser, name):
interface.nav_to_module(browser, 'users') interface.nav_to_module(browser, 'users')
user_link = browser.find_link_by_href( user_link = browser.find_link_by_href('/plinth/sys/users/' + name +
'/plinth/sys/users/' + name + '/edit/') '/edit/')
if not user_link: if not user_link:
create_user(browser, name, 'secret123') create_user(browser, name, 'secret123')

View File

@ -61,8 +61,9 @@ def verify_upload_password(browser, password):
'I upload the sample local file to coquelicot with password {password:w}' 'I upload the sample local file to coquelicot with password {password:w}'
)) ))
def coquelicot_upload_file(browser, sample_local_file, password): def coquelicot_upload_file(browser, sample_local_file, password):
url = site.upload_file_to_coquelicot( url = site.upload_file_to_coquelicot(browser,
browser, sample_local_file['file_path'], password) sample_local_file['file_path'],
password)
sample_local_file['upload_url'] = url sample_local_file['upload_url'] = url
@ -214,7 +215,8 @@ def syncthing_folder_not_present(browser, folder_name):
@given( @given(
parsers.parse( parsers.parse(
'folder {folder_path:S} is present as syncthing folder {folder_name:w}')) 'folder {folder_path:S} is present as syncthing folder {folder_name:w}'
))
def syncthing_folder_present(browser, folder_name, folder_path): def syncthing_folder_present(browser, folder_name, folder_path):
if not site.syncthing_folder_is_present(browser, folder_name): if not site.syncthing_folder_is_present(browser, folder_name):
site.syncthing_add_folder(browser, folder_name, folder_path) site.syncthing_add_folder(browser, folder_name, folder_path)

View File

@ -294,8 +294,8 @@ def transmission_remove_all_torrents(browser):
def transmission_upload_sample_torrent(browser): def transmission_upload_sample_torrent(browser):
"""Upload a sample torrent into transmission.""" """Upload a sample torrent into transmission."""
browser.visit(config['DEFAULT']['url'] + '/transmission') browser.visit(config['DEFAULT']['url'] + '/transmission')
file_path = os.path.join( file_path = os.path.join(os.path.dirname(__file__), '..', 'data',
os.path.dirname(__file__), '..', 'data', 'sample.torrent') 'sample.torrent')
browser.click_link_by_id('toolbar-open') browser.click_link_by_id('toolbar-open')
eventually(browser.is_element_not_present_by_css, eventually(browser.is_element_not_present_by_css,
args=['#upload-container[style="display: none;"]']) args=['#upload-container[style="display: none;"]'])
@ -396,9 +396,8 @@ def deluge_remove_all_torrents(browser):
browser.find_by_id('remove').first.click() browser.find_by_id('remove').first.click()
# Remove window shows up # Remove window shows up
assert eventually( assert eventually(lambda: _deluge_get_active_window_title(browser) ==
lambda: _deluge_get_active_window_title(browser) == 'Remove Torrent' 'Remove Torrent')
)
_deluge_click_active_window_button(browser, 'Remove With Data') _deluge_click_active_window_button(browser, 'Remove With Data')
@ -434,8 +433,8 @@ def deluge_upload_sample_torrent(browser):
eventually( eventually(
lambda: _deluge_get_active_window_title(browser) == 'Add Torrents') lambda: _deluge_get_active_window_title(browser) == 'Add Torrents')
file_path = os.path.join( file_path = os.path.join(os.path.dirname(__file__), '..', 'data',
os.path.dirname(__file__), '..', 'data', 'sample.torrent') 'sample.torrent')
if browser.find_by_id('fileUploadForm'): # deluge-web 2.x if browser.find_by_id('fileUploadForm'): # deluge-web 2.x
browser.attach_file('file', file_path) browser.attach_file('file', file_path)
@ -443,9 +442,8 @@ def deluge_upload_sample_torrent(browser):
browser.find_by_css('button.x-deluge-add-file').first.click() browser.find_by_css('button.x-deluge-add-file').first.click()
# Add from file window appears # Add from file window appears
eventually( eventually(lambda: _deluge_get_active_window_title(browser) ==
lambda: _deluge_get_active_window_title(browser) == 'Add from File' 'Add from File')
)
# Attach file # Attach file
browser.attach_file('file', file_path) browser.attach_file('file', file_path)

View File

@ -211,7 +211,6 @@ def webserver_disable(name, kind='config', apply_changes=True):
class WebserverChange(object): class WebserverChange(object):
"""Context to restart/reload Apache after configuration changes.""" """Context to restart/reload Apache after configuration changes."""
def __init__(self): def __init__(self):
"""Initialize the context object state.""" """Initialize the context object state."""
self.actions_required = set() self.actions_required = set()
@ -425,9 +424,10 @@ def diagnose_url_on_all(url, **kwargs):
def diagnose_netcat(host, port, input='', negate=False): def diagnose_netcat(host, port, input='', negate=False):
"""Run a diagnostic using netcat.""" """Run a diagnostic using netcat."""
try: try:
process = subprocess.Popen( process = subprocess.Popen(['nc', host, str(port)],
['nc', host, str(port)], stdin=subprocess.PIPE, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
process.communicate(input=input.encode()) process.communicate(input=input.encode())
if process.returncode != 0: if process.returncode != 0:
result = 'failed' result = 'failed'

View File

@ -114,7 +114,6 @@ class Component:
def enable(self): def enable(self):
"""Run operations to enable the component.""" """Run operations to enable the component."""
def disable(self): def disable(self):
"""Run operations to disable the component.""" """Run operations to disable the component."""

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Django context processors to provide common data to templates. Django context processors to provide common data to templates.
""" """

View File

@ -23,7 +23,6 @@ from plinth import action_utils, actions, app
class Daemon(app.LeaderComponent): class Daemon(app.LeaderComponent):
"""Component to manage a background daemon or any systemd unit.""" """Component to manage a background daemon or any systemd unit."""
def __init__(self, component_id, unit, strict_check=False): def __init__(self, component_id, unit, strict_check=False):
"""Initialize a new daemon component. """Initialize a new daemon component.

View File

@ -83,7 +83,6 @@ class PackageHandler():
class DBusServer(): class DBusServer():
"""Abstraction over a connection to D-Bus.""" """Abstraction over a connection to D-Bus."""
def __init__(self): def __init__(self):
"""Initialize the server object.""" """Initialize the server object."""
self.package_handler = None self.package_handler = None

View File

@ -43,7 +43,6 @@ class DomainSelectionForm(forms.Form):
"""Form for selecting a domain name to be used for """Form for selecting a domain name to be used for
distributed federated applications distributed federated applications
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -84,9 +83,9 @@ class LanguageSelectionFormMixin:
plinth_dir = os.path.dirname(plinth.__file__) plinth_dir = os.path.dirname(plinth.__file__)
if language_code == 'en' or os.path.exists( if language_code == 'en' or os.path.exists(
os.path.join(plinth_dir, 'locale', locale_code)): os.path.join(plinth_dir, 'locale', locale_code)):
supported_languages.append((language_code, supported_languages.append(
_get_local_name( (language_code,
language_code, language_name))) _get_local_name(language_code, language_name)))
self.fields['language'].choices = supported_languages self.fields['language'].choices = supported_languages
@ -106,7 +105,6 @@ class CheckboxSelectMultipleWithReadOnly(forms.widgets.CheckboxSelectMultiple):
Derived from https://djangosnippets.org/snippets/2786/ Derived from https://djangosnippets.org/snippets/2786/
""" """
def render(self, name, value, attrs=None, choices=(), renderer=None): def render(self, name, value, attrs=None, choices=(), renderer=None):
if value is None: if value is None:
value = [] value = []
@ -114,8 +112,8 @@ class CheckboxSelectMultipleWithReadOnly(forms.widgets.CheckboxSelectMultiple):
output = [u'<ul>'] output = [u'<ul>']
global_readonly = 'readonly' in final_attrs global_readonly = 'readonly' in final_attrs
str_values = set([v for v in value]) str_values = set([v for v in value])
for i, (option_value, option_label) in enumerate( for i, (option_value,
chain(self.choices, choices)): option_label) in enumerate(chain(self.choices, choices)):
if not global_readonly and 'readonly' in final_attrs: if not global_readonly and 'readonly' in final_attrs:
# If the entire group is readonly keep all options readonly # If the entire group is readonly keep all options readonly
del final_attrs['readonly'] del final_attrs['readonly']

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Simple key/value store using Django models Simple key/value store using Django models
""" """

View File

@ -41,7 +41,6 @@ logger = logging.getLogger(__name__)
class SetupMiddleware(MiddlewareMixin): class SetupMiddleware(MiddlewareMixin):
"""Django middleware to show pre-setup message and setup progress.""" """Django middleware to show pre-setup message and setup progress."""
@staticmethod @staticmethod
def process_view(request, view_func, view_args, view_kwargs): def process_view(request, view_func, view_args, view_kwargs):
"""Handle a request as Django middleware request handler.""" """Handle a request as Django middleware request handler."""
@ -77,8 +76,8 @@ class SetupMiddleware(MiddlewareMixin):
str(exception)) str(exception))
error_details = getattr(exception, 'error_details', '') error_details = getattr(exception, 'error_details', '')
message = _('Error installing application: {string} ' message = _('Error installing application: {string} '
'{details}').format( '{details}').format(string=error_string,
string=error_string, details=error_details) details=error_details)
else: else:
message = _('Error installing application: {error}') \ message = _('Error installing application: {error}') \
.format(error=exception) .format(error=exception)
@ -96,7 +95,6 @@ class SetupMiddleware(MiddlewareMixin):
class AdminRequiredMiddleware(MiddlewareMixin): class AdminRequiredMiddleware(MiddlewareMixin):
"""Django middleware for authenticating requests for admin areas.""" """Django middleware for authenticating requests for admin areas."""
@staticmethod @staticmethod
def process_view(request, view_func, view_args, view_kwargs): def process_view(request, view_func, view_args, view_kwargs):
"""Reject non-admin access to views that are private and not marked.""" """Reject non-admin access to views that are private and not marked."""
@ -110,7 +108,6 @@ class AdminRequiredMiddleware(MiddlewareMixin):
class FirstSetupMiddleware(MiddlewareMixin): class FirstSetupMiddleware(MiddlewareMixin):
"""Django middleware to block all interactions before first setup.""" """Django middleware to block all interactions before first setup."""
@staticmethod @staticmethod
def process_view(request, view_func, view_args, view_kwargs): def process_view(request, view_func, view_args, view_kwargs):
"""Block all user interactions when first setup is pending.""" """Block all user interactions when first setup is pending."""

View File

@ -18,7 +18,6 @@
# #
# Generated by Django 1.9 on 2015-12-04 07:27 # Generated by Django 1.9 on 2015-12-04 07:27
# #
""" """
Initial Django migration for FreedomBox to create database tables. Initial Django migration for FreedomBox to create database tables.
""" """
@ -33,8 +32,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Remove the deprecated KVStore entries 'setup_state' and 'firstboot_state', Remove the deprecated KVStore entries 'setup_state' and 'firstboot_state',
and only use the new entry 'firstboot_completed' instead. and only use the new entry 'firstboot_completed' instead.
@ -63,8 +62,8 @@ def merge_firstboot_finished_fields(apps, schema_editor):
firstboot_completed = _object.value firstboot_completed = _object.value
# Set new 'firstboot_completed' if needed # Set new 'firstboot_completed' if needed
new_firstboot_completed = bool(firstboot_completed or setup_state or new_firstboot_completed = bool(firstboot_completed or setup_state
firstboot_state) or firstboot_state)
if new_firstboot_completed and not firstboot_completed: if new_firstboot_completed and not firstboot_completed:
obj, created = KVStore.objects.get_or_create(key='firstboot_completed') obj, created = KVStore.objects.get_or_create(key='firstboot_completed')
obj.value = 1 obj.value = 1

View File

@ -30,14 +30,17 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='UserProfile', name='UserProfile',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, ('id',
serialize=False, verbose_name='ID')), models.AutoField(auto_created=True, primary_key=True,
('language', models.CharField(default=None, max_length=32, serialize=False, verbose_name='ID')),
null=True)), ('language',
('user', models.OneToOneField( models.CharField(default=None, max_length=32, null=True)),
on_delete=django.db.models.deletion.CASCADE, ('user',
to=settings.AUTH_USER_MODEL)), models.OneToOneField(
], ), on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL)),
],
),
migrations.RunPython(code=insert_users, migrations.RunPython(code=insert_users,
reverse_code=truncate_user_profile), reverse_code=truncate_user_profile),
] ]

View File

@ -54,9 +54,9 @@ class ApacheApp(app_module.App):
freedombox_ports = Firewall( freedombox_ports = Firewall(
'firewall-plinth', 'firewall-plinth',
format_lazy( format_lazy(_('{box_name} Web Interface (Plinth)'),
_('{box_name} Web Interface (Plinth)'), box_name=_( box_name=_(cfg.box_name)), ports=['http', 'https'],
cfg.box_name)), ports=['http', 'https'], is_external=True) is_external=True)
self.add(freedombox_ports) self.add(freedombox_ports)
letsencrypt = LetsEncrypt('letsencrypt-apache', domains='*', letsencrypt = LetsEncrypt('letsencrypt-apache', domains='*',

View File

@ -23,7 +23,6 @@ from plinth import action_utils, actions, app
class Webserver(app.LeaderComponent): class Webserver(app.LeaderComponent):
"""Component to enable/disable Apache configuration.""" """Component to enable/disable Apache configuration."""
def __init__(self, component_id, web_name, kind='config'): def __init__(self, component_id, web_name, kind='config'):
"""Initialize the web server component. """Initialize the web server component.
@ -62,7 +61,6 @@ class Webserver(app.LeaderComponent):
class Uwsgi(app.LeaderComponent): class Uwsgi(app.LeaderComponent):
"""Component to enable/disable uWSGI configuration.""" """Component to enable/disable uWSGI configuration."""
def __init__(self, component_id, uwsgi_name): def __init__(self, component_id, uwsgi_name):
"""Initialize the uWSGI component. """Initialize the uWSGI component.

View File

@ -14,10 +14,8 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the Apache module. URLs for the Apache module.
""" """
urlpatterns = [ urlpatterns = []
]

View File

@ -45,9 +45,8 @@ def shortcuts(request, **kwargs):
# XXX: Get the module (or module name) from shortcut properly. # XXX: Get the module (or module name) from shortcut properly.
username = str(request.user) if request.user.is_authenticated else None username = str(request.user) if request.user.is_authenticated else None
response = get_shortcuts_as_json(username) response = get_shortcuts_as_json(username)
return HttpResponse( return HttpResponse(json.dumps(response, cls=DjangoJSONEncoder),
json.dumps(response, cls=DjangoJSONEncoder), content_type='application/json')
content_type='application/json')
def get_shortcuts_as_json(username=None): def get_shortcuts_as_json(username=None):

View File

@ -91,9 +91,10 @@ def init():
global app global app
app = AvahiApp() app = AvahiApp()
if app.is_enabled(): if app.is_enabled():
domain_added.send_robust( domain_added.send_robust(sender='avahi',
sender='avahi', domain_type='domain-type-local', domain_type='domain-type-local',
name=get_hostname() + '.local', services='__all__') name=get_hostname() + '.local',
services='__all__')
app.set_enabled(True) app.set_enabled(True)
post_hostname_change.connect(on_post_hostname_change) post_hostname_change.connect(on_post_hostname_change)

View File

@ -108,9 +108,8 @@ def _backup_handler(packet, encryption_passphrase=None):
arguments = ['create-archive', '--path', packet.path, '--paths'] + paths arguments = ['create-archive', '--path', packet.path, '--paths'] + paths
input_data = '' input_data = ''
if encryption_passphrase: if encryption_passphrase:
input_data = json.dumps({ input_data = json.dumps(
'encryption_passphrase': encryption_passphrase {'encryption_passphrase': encryption_passphrase})
})
actions.superuser_run('backups', arguments, input=input_data.encode()) actions.superuser_run('backups', arguments, input=input_data.encode())

View File

@ -82,7 +82,6 @@ def _validate_service(service):
class BackupError: class BackupError:
"""Represent an backup/restore operation error.""" """Represent an backup/restore operation error."""
def __init__(self, error_type, app, hook=None): def __init__(self, error_type, app, hook=None):
"""Initialize the error object.""" """Initialize the error object."""
self.error_type = error_type self.error_type = error_type
@ -98,7 +97,6 @@ class BackupError:
class Packet: class Packet:
"""Information passed to a handlers for backup/restore operations.""" """Information passed to a handlers for backup/restore operations."""
def __init__(self, operation, scope, root, apps=None, path=None): def __init__(self, operation, scope, root, apps=None, path=None):
"""Initialize the packet. """Initialize the packet.
@ -240,7 +238,6 @@ def _install_apps_before_restore(apps):
class BackupApp: class BackupApp:
"""A application that can be backed up and its manifest.""" """A application that can be backed up and its manifest."""
def __init__(self, name, app): def __init__(self, name, app):
"""Initialize object and load manfiest.""" """Initialize object and load manfiest."""
self.name = name self.name = name
@ -365,7 +362,6 @@ def _switch_to_subvolume(subvolume):
class ServiceHandler: class ServiceHandler:
"""Abstraction to help with service shutdown/restart.""" """Abstraction to help with service shutdown/restart."""
@staticmethod @staticmethod
def create(backup_app, service): def create(backup_app, service):
service_type = 'system' service_type = 'system'
@ -400,7 +396,6 @@ class ServiceHandler:
class SystemServiceHandler(ServiceHandler): class SystemServiceHandler(ServiceHandler):
"""Handle starting and stopping of system services for backup.""" """Handle starting and stopping of system services for backup."""
def __init__(self, backup_app, service): def __init__(self, backup_app, service):
"""Initialize the object.""" """Initialize the object."""
super().__init__(backup_app, service) super().__init__(backup_app, service)
@ -420,7 +415,6 @@ class SystemServiceHandler(ServiceHandler):
class ApacheServiceHandler(ServiceHandler): class ApacheServiceHandler(ServiceHandler):
"""Handle starting and stopping of Apache services for backup.""" """Handle starting and stopping of Apache services for backup."""
def __init__(self, backup_app, service): def __init__(self, backup_app, service):
"""Initialize the object.""" """Initialize the object."""
super().__init__(backup_app, service) super().__init__(backup_app, service)

View File

@ -30,7 +30,6 @@ def delete_tmp_backup_file(function):
XXX: Implement a better way to delete uploaded files. XXX: Implement a better way to delete uploaded files.
""" """
@functools.wraps(function) @functools.wraps(function)
def wrapper(request, *args, **kwargs): def wrapper(request, *args, **kwargs):
path = request.session.get(SESSION_PATH_VARIABLE, None) path = request.session.get(SESSION_PATH_VARIABLE, None)

View File

@ -59,10 +59,8 @@ KNOWN_ERRORS = [
'errors': [ 'errors': [
'not a valid repository', 'does not exist', 'FileNotFoundError' 'not a valid repository', 'does not exist', 'FileNotFoundError'
], ],
'message': 'message': _('Repository not found'),
_('Repository not found'), 'raise_as': errors.BorgRepositoryDoesNotExistError,
'raise_as':
errors.BorgRepositoryDoesNotExistError,
}, },
{ {
'errors': ['passphrase supplied in .* is incorrect'], 'errors': ['passphrase supplied in .* is incorrect'],
@ -176,7 +174,6 @@ class BaseBorgRepository(abc.ABC):
def remove(self): def remove(self):
"""Remove a borg repository""" """Remove a borg repository"""
def list_archives(self): def list_archives(self):
"""Return list of archives in this repository.""" """Return list of archives in this repository."""
output = self.run(['list-repo', '--path', self.borg_path]) output = self.run(['list-repo', '--path', self.borg_path])
@ -241,7 +238,6 @@ class BaseBorgRepository(abc.ABC):
def get_download_stream(self, archive_name): def get_download_stream(self, archive_name):
"""Return an stream of .tar.gz binary data for a backup archive.""" """Return an stream of .tar.gz binary data for a backup archive."""
class BufferedReader(io.BufferedReader): class BufferedReader(io.BufferedReader):
"""Improve performance of buffered binary streaming. """Improve performance of buffered binary streaming.
@ -255,7 +251,6 @@ class BaseBorgRepository(abc.ABC):
binary data. binary data.
""" """
def __next__(self): def __next__(self):
"""Override to call read() instead of readline().""" """Override to call read() instead of readline()."""
chunk = self.read(io.DEFAULT_BUFFER_SIZE) chunk = self.read(io.DEFAULT_BUFFER_SIZE)

View File

@ -57,7 +57,6 @@ def _get_backup_app(name):
class TestBackupApp: class TestBackupApp:
"""Test the BackupApp class.""" """Test the BackupApp class."""
@staticmethod @staticmethod
def test_run_hook(): def test_run_hook():
"""Test running a hook on an application.""" """Test running a hook on an application."""
@ -82,7 +81,6 @@ class TestBackupApp:
@pytest.mark.usefixtures('load_cfg') @pytest.mark.usefixtures('load_cfg')
class TestBackupProcesses: class TestBackupProcesses:
"""Test cases for backup processes""" """Test cases for backup processes"""
@staticmethod @staticmethod
def test_packet_process_manifests(): def test_packet_process_manifests():
"""Test that directories/files are collected from manifests.""" """Test that directories/files are collected from manifests."""
@ -239,7 +237,6 @@ class TestBackupProcesses:
class TestBackupModule: class TestBackupModule:
"""Tests of the backups django module, like views or forms.""" """Tests of the backups django module, like views or forms."""
@staticmethod @staticmethod
def test_file_upload(): def test_file_upload():
# posting a video should fail # posting a video should fail

View File

@ -27,8 +27,8 @@ CONFIG_FILE = '/etc/cockpit/cockpit.conf'
def load_augeas(): def load_augeas():
"""Initialize Augeas.""" """Initialize Augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/inifile/lens', 'Puppet.lns') aug.set('/augeas/load/inifile/lens', 'Puppet.lns')
aug.set('/augeas/load/inifile/incl[last() + 1]', CONFIG_FILE) aug.set('/augeas/load/inifile/incl[last() + 1]', CONFIG_FILE)
aug.load() aug.load()

View File

@ -81,8 +81,8 @@ def get_hostname():
def _get_home_page_url(): def _get_home_page_url():
"""Get the default application for the domain.""" """Get the default application for the domain."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') aug.set('/augeas/load/Httpd/lens', 'Httpd.lns')
conf_file = APACHE_HOMEPAGE_CONFIG if os.path.exists( conf_file = APACHE_HOMEPAGE_CONFIG if os.path.exists(
APACHE_HOMEPAGE_CONFIG) else FREEDOMBOX_APACHE_CONFIG APACHE_HOMEPAGE_CONFIG) else FREEDOMBOX_APACHE_CONFIG

View File

@ -67,11 +67,10 @@ class ConfigurationForm(forms.Form):
'end with an alphabet or a digit and have as interior ' 'end with an alphabet or a digit and have as interior '
'characters only alphabets, digits and hyphens. Total ' 'characters only alphabets, digits and hyphens. Total '
'length must be 63 characters or less.'), 'length must be 63 characters or less.'),
box_name=ugettext_lazy(cfg.box_name)), box_name=ugettext_lazy(cfg.box_name)), validators=[
validators=[ validators.RegexValidator(HOSTNAME_REGEX,
validators.RegexValidator(HOSTNAME_REGEX, ugettext_lazy('Invalid hostname'))
ugettext_lazy('Invalid hostname')) ], strip=True)
], strip=True)
domainname = forms.CharField( domainname = forms.CharField(
label=ugettext_lazy('Domain Name'), help_text=format_lazy( label=ugettext_lazy('Domain Name'), help_text=format_lazy(
@ -83,12 +82,12 @@ class ConfigurationForm(forms.Form):
'only alphabets, digits and hyphens. Length of each label ' 'only alphabets, digits and hyphens. Length of each label '
'must be 63 characters or less. Total length of domain name ' 'must be 63 characters or less. Total length of domain name '
'must be 253 characters or less.'), 'must be 253 characters or less.'),
box_name=ugettext_lazy(cfg.box_name)), box_name=ugettext_lazy(cfg.box_name)), required=False, validators=[
required=False, validators=[ validators.RegexValidator(
validators.RegexValidator( r'^[a-zA-Z0-9]([-a-zA-Z0-9.]{,251}[a-zA-Z0-9])?$',
r'^[a-zA-Z0-9]([-a-zA-Z0-9.]{,251}[a-zA-Z0-9])?$', ugettext_lazy('Invalid domain name')),
ugettext_lazy('Invalid domain name')), domain_label_validator domain_label_validator
], strip=True) ], strip=True)
homepage = forms.ChoiceField( homepage = forms.ChoiceField(
label=ugettext_lazy('Webserver Home Page'), help_text=format_lazy( label=ugettext_lazy('Webserver Home Page'), help_text=format_lazy(

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the Diagnostics module URLs for the Diagnostics module
""" """
@ -23,7 +22,6 @@ from django.conf.urls import url
from . import diagnostics as views from . import diagnostics as views
urlpatterns = [ urlpatterns = [
url(r'^sys/diagnostics/$', views.index, name='index'), url(r'^sys/diagnostics/$', views.index, name='index'),
url(r'^sys/diagnostics/(?P<module_name>[1-9a-z\-]+)/$', views.module, url(r'^sys/diagnostics/(?P<module_name>[1-9a-z\-]+)/$', views.module,

View File

@ -89,9 +89,10 @@ class DiasporaApp(app_module.App):
parent_url_name='apps') parent_url_name='apps')
self.add(menu_item) self.add(menu_item)
shortcut = Shortcut( shortcut = Shortcut('shortcut-diaspora', name,
'shortcut-diaspora', name, short_description=short_description, short_description=short_description,
icon='diaspora', url=None, clients=clients, login_required=True) icon='diaspora', url=None, clients=clients,
login_required=True)
self.add(shortcut) self.add(shortcut)
firewall = Firewall('firewall-diaspora', name, ports=['http', 'https'], firewall = Firewall('firewall-diaspora', name, ports=['http', 'https'],
@ -107,7 +108,6 @@ class DiasporaApp(app_module.App):
class Shortcut(frontpage.Shortcut): class Shortcut(frontpage.Shortcut):
"""Frontpage shortcut to use configured domain name for URL.""" """Frontpage shortcut to use configured domain name for URL."""
def enable(self): def enable(self):
"""Set the proper shortcut URL when enabled.""" """Set the proper shortcut URL when enabled."""
super().enable() super().enable()
@ -179,8 +179,8 @@ def generate_apache_configuration(conf_file, domain_name):
diaspora_domain_name = ".".join(["diaspora", domain_name]) diaspora_domain_name = ".".join(["diaspora", domain_name])
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') aug.set('/augeas/load/Httpd/lens', 'Httpd.lns')
aug.set('/augeas/load/Httpd/incl[last() + 1]', conf_file) aug.set('/augeas/load/Httpd/incl[last() + 1]', conf_file)

View File

@ -40,8 +40,9 @@ clients = validate([{
'type': 'type':
'web', 'web',
'url': 'url':
format_lazy('https://diaspora.{host}', format_lazy(
host=diaspora.get_configured_domain_name() if 'https://diaspora.{host}',
diaspora.is_setup() else "<please-setup-domain-name>") host=diaspora.get_configured_domain_name()
if diaspora.is_setup() else "<please-setup-domain-name>")
}] }]
}]) }])

View File

@ -86,9 +86,10 @@ def init():
app = DynamicDNSApp() app = DynamicDNSApp()
current_status = get_status() current_status = get_status()
if current_status['enabled']: if current_status['enabled']:
domain_added.send_robust( domain_added.send_robust(sender='dynamicdns',
sender='dynamicdns', domain_type='domain-type-dynamic', domain_type='domain-type-dynamic',
name=current_status['dynamicdns_domain'], services='__all__') name=current_status['dynamicdns_domain'],
services='__all__')
app.set_enabled(True) app.set_enabled(True)

View File

@ -28,7 +28,6 @@ from plinth.utils import format_lazy
class TrimmedCharField(forms.CharField): class TrimmedCharField(forms.CharField):
"""Trim the contents of a CharField.""" """Trim the contents of a CharField."""
def clean(self, value): def clean(self, value):
"""Clean and validate the field value""" """Clean and validate the field value"""
if value: if value:
@ -81,12 +80,12 @@ class ConfigureForm(forms.Form):
'freedns.afraid.org'), 'freedns.afraid.org'),
('other', 'other update URL')) ('other', 'other update URL'))
enabled = forms.BooleanField( enabled = forms.BooleanField(label=ugettext_lazy('Enable Dynamic DNS'),
label=ugettext_lazy('Enable Dynamic DNS'), required=False) required=False)
service_type = forms.ChoiceField( service_type = forms.ChoiceField(label=ugettext_lazy('Service Type'),
label=ugettext_lazy('Service Type'), help_text=help_services, help_text=help_services,
choices=provider_choices) choices=provider_choices)
dynamicdns_server = TrimmedCharField( dynamicdns_server = TrimmedCharField(
label=ugettext_lazy('GnuDIP Server Address'), required=False, label=ugettext_lazy('GnuDIP Server Address'), required=False,
@ -95,9 +94,9 @@ class ConfigureForm(forms.Form):
ugettext_lazy('Invalid server name')) ugettext_lazy('Invalid server name'))
]) ])
dynamicdns_update_url = TrimmedCharField( dynamicdns_update_url = TrimmedCharField(label=ugettext_lazy('Update URL'),
label=ugettext_lazy('Update URL'), required=False, required=False,
help_text=help_update_url) help_text=help_update_url)
disable_SSL_cert_check = forms.BooleanField( disable_SSL_cert_check = forms.BooleanField(
label=ugettext_lazy('Accept all SSL certificates'), label=ugettext_lazy('Accept all SSL certificates'),
@ -114,15 +113,15 @@ class ConfigureForm(forms.Form):
ugettext_lazy('Invalid domain name')) ugettext_lazy('Invalid domain name'))
]) ])
dynamicdns_user = TrimmedCharField( dynamicdns_user = TrimmedCharField(label=ugettext_lazy('Username'),
label=ugettext_lazy('Username'), required=False, help_text=help_user) required=False, help_text=help_user)
dynamicdns_secret = TrimmedCharField( dynamicdns_secret = TrimmedCharField(label=ugettext_lazy('Password'),
label=ugettext_lazy('Password'), widget=forms.PasswordInput(), widget=forms.PasswordInput(),
required=False, help_text=help_secret) required=False, help_text=help_secret)
showpw = forms.BooleanField( showpw = forms.BooleanField(label=ugettext_lazy('Show password'),
label=ugettext_lazy('Show password'), required=False) required=False)
dynamicdns_ipurl = TrimmedCharField( dynamicdns_ipurl = TrimmedCharField(
label=ugettext_lazy('URL to look up public IP'), required=False, label=ugettext_lazy('URL to look up public IP'), required=False,

View File

@ -39,15 +39,13 @@ EMPTYSTRING = 'none'
subsubmenu = [{ subsubmenu = [{
'url': reverse_lazy('dynamicdns:index'), 'url': reverse_lazy('dynamicdns:index'),
'text': ugettext_lazy('About') 'text': ugettext_lazy('About')
}, }, {
{ 'url': reverse_lazy('dynamicdns:configure'),
'url': reverse_lazy('dynamicdns:configure'), 'text': ugettext_lazy('Configure')
'text': ugettext_lazy('Configure') }, {
}, 'url': reverse_lazy('dynamicdns:statuspage'),
{ 'text': ugettext_lazy('Status')
'url': reverse_lazy('dynamicdns:statuspage'), }]
'text': ugettext_lazy('Status')
}]
def index(request): def index(request):
@ -164,9 +162,10 @@ def _apply_changes(request, old_status, new_status):
_run(['stop']) _run(['stop'])
if new_status['enabled']: if new_status['enabled']:
domain_added.send_robust( domain_added.send_robust(sender='dynamicdns',
sender='dynamicdns', domain_type='domain-type-dynamic', domain_type='domain-type-dynamic',
name=new_status['dynamicdns_domain'], services='__all__') name=new_status['dynamicdns_domain'],
services='__all__')
_run(['start']) _run(['start'])
messages.success(request, _('Configuration updated')) messages.success(request, _('Configuration updated'))

View File

@ -77,7 +77,6 @@ def test_port_details(get_port_details):
@patch('plinth.modules.firewall.get_enabled_services') @patch('plinth.modules.firewall.get_enabled_services')
def test_enable(get_enabled_services, add_service): def test_enable(get_enabled_services, add_service):
"""Test enabling a firewall component.""" """Test enabling a firewall component."""
def get_enabled_services_side_effect(zone): def get_enabled_services_side_effect(zone):
return {'internal': ['test-port1'], 'external': ['test-port2']}[zone] return {'internal': ['test-port1'], 'external': ['test-port2']}[zone]

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the Firewall module URLs for the Firewall module
""" """
@ -23,7 +22,6 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^sys/firewall/$', views.index, name='index'), url(r'^sys/firewall/$', views.index, name='index'),
] ]

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Django middleware to redirect to firstboot wizard if it has not be run Django middleware to redirect to firstboot wizard if it has not be run
yet. yet.
@ -34,7 +33,6 @@ LOGGER = logging.getLogger(__name__)
class FirstBootMiddleware(MiddlewareMixin): class FirstBootMiddleware(MiddlewareMixin):
"""Forward to firstboot page if firstboot isn't finished yet.""" """Forward to firstboot page if firstboot isn't finished yet."""
@staticmethod @staticmethod
def process_request(request): def process_request(request):
"""Handle a request as Django middleware request handler.""" """Handle a request as Django middleware request handler."""

View File

@ -78,10 +78,11 @@ class GitwebApp(app_module.App):
'gitweb:index', parent_url_name='apps') 'gitweb:index', parent_url_name='apps')
self.add(menu_item) self.add(menu_item)
shortcut = frontpage.Shortcut( shortcut = frontpage.Shortcut('shortcut-gitweb', name,
'shortcut-gitweb', name, short_description=short_description, short_description=short_description,
icon=icon_filename, url='/gitweb/', clients=clients, icon=icon_filename, url='/gitweb/',
login_required=True, allowed_groups=[group[0]]) clients=clients, login_required=True,
allowed_groups=[group[0]])
self.add(shortcut) self.add(shortcut)
firewall = Firewall('firewall-gitweb', name, ports=['http', 'https'], firewall = Firewall('firewall-gitweb', name, ports=['http', 'https'],
@ -154,7 +155,6 @@ class GitwebApp(app_module.App):
class GitwebWebserverAuth(Webserver): class GitwebWebserverAuth(Webserver):
"""Component to handle Gitweb authentication webserver configuration.""" """Component to handle Gitweb authentication webserver configuration."""
def is_conf_enabled(self): def is_conf_enabled(self):
"""Check whether Gitweb authentication configuration is enabled.""" """Check whether Gitweb authentication configuration is enabled."""
return super().is_enabled() return super().is_enabled()

View File

@ -83,9 +83,9 @@ class CreateRepoForm(forms.Form):
label=_('Description of the repository'), strip=True, required=False, label=_('Description of the repository'), strip=True, required=False,
help_text=_('Optional, for displaying on Gitweb.')) help_text=_('Optional, for displaying on Gitweb.'))
owner = forms.CharField( owner = forms.CharField(label=_('Repository\'s owner name'), strip=True,
label=_('Repository\'s owner name'), strip=True, required=False, required=False,
help_text=_('Optional, for displaying on Gitweb.')) help_text=_('Optional, for displaying on Gitweb.'))
is_private = forms.BooleanField( is_private = forms.BooleanField(
label=_('Private repository'), required=False, label=_('Private repository'), required=False,

View File

@ -30,8 +30,8 @@ from django.forms import ValidationError
def _action_file(): def _action_file():
"""Return the path to the 'gitweb' actions file.""" """Return the path to the 'gitweb' actions file."""
current_directory = pathlib.Path(__file__).parent current_directory = pathlib.Path(__file__).parent
return str( return str(current_directory / '..' / '..' / '..' / '..' / 'actions' /
current_directory / '..' / '..' / '..' / '..' / 'actions' / 'gitweb') 'gitweb')
gitweb_actions = imp.load_source('gitweb', _action_file()) gitweb_actions = imp.load_source('gitweb', _action_file())
@ -40,7 +40,6 @@ gitweb_actions = imp.load_source('gitweb', _action_file())
@pytest.fixture(name='call_action') @pytest.fixture(name='call_action')
def fixture_call_action(tmpdir, capsys): def fixture_call_action(tmpdir, capsys):
"""Run actions with custom repo root path.""" """Run actions with custom repo root path."""
def _call_action(args, **kwargs): def _call_action(args, **kwargs):
gitweb_actions.GIT_REPO_PATH = str(tmpdir) gitweb_actions.GIT_REPO_PATH = str(tmpdir)
with patch('argparse._sys.argv', ['gitweb'] + args): with patch('argparse._sys.argv', ['gitweb'] + args):

View File

@ -89,10 +89,11 @@ class I2PApp(app_module.App):
'i2p:index', parent_url_name='apps') 'i2p:index', parent_url_name='apps')
self.add(menu_item) self.add(menu_item)
shortcut = frontpage.Shortcut( shortcut = frontpage.Shortcut('shortcut-i2p', name,
'shortcut-i2p', name, short_description=short_description, short_description=short_description,
icon=icon_filename, url='/i2p/', clients=clients, login_required=True, icon=icon_filename, url='/i2p/',
allowed_groups=[group[0]]) clients=clients, login_required=True,
allowed_groups=[group[0]])
self.add(shortcut) self.add(shortcut)
firewall = Firewall('firewall-i2p-web', name, ports=['http', 'https'], firewall = Firewall('firewall-i2p-web', name, ports=['http', 'https'],

View File

@ -35,7 +35,6 @@ class TunnelEditor():
:type aug: augeas.Augeas :type aug: augeas.Augeas
""" """
def __init__(self, conf_filename=None, idx=None): def __init__(self, conf_filename=None, idx=None):
self.conf_filename = conf_filename or FILE_TUNNEL_CONF self.conf_filename = conf_filename or FILE_TUNNEL_CONF
self.idx = idx self.idx = idx
@ -55,8 +54,8 @@ class TunnelEditor():
Chainable method. Chainable method.
""" """
self.aug = augeas.Augeas( self.aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
self.aug.set('/augeas/load/Properties/lens', 'Properties.lns') self.aug.set('/augeas/load/Properties/lens', 'Properties.lns')
self.aug.set('/augeas/load/Properties/incl[last() + 1]', self.aug.set('/augeas/load/Properties/incl[last() + 1]',
self.conf_filename) self.conf_filename)
@ -160,8 +159,8 @@ class RouterEditor():
Chainable method. Chainable method.
""" """
self.aug = augeas.Augeas( self.aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
self.aug.set('/augeas/load/Properties/lens', 'Properties.lns') self.aug.set('/augeas/load/Properties/lens', 'Properties.lns')
self.aug.set('/augeas/load/Properties/incl[last() + 1]', self.aug.set('/augeas/load/Properties/incl[last() + 1]',
self.conf_filename) self.conf_filename)

View File

@ -18,110 +18,92 @@
Pre-defined list of favorites for I2P and some additional favorites. Pre-defined list of favorites for I2P and some additional favorites.
""" """
DEFAULT_FAVORITES = [ DEFAULT_FAVORITES = [{
{ 'name': 'anoncoin.i2p',
'name': 'anoncoin.i2p', 'description': 'The Anoncoin project',
'description': 'The Anoncoin project', 'icon': '/themes/console/images/anoncoin_32.png',
'icon': '/themes/console/images/anoncoin_32.png', 'url': 'http://anoncoin.i2p/'
'url': 'http://anoncoin.i2p/' }, {
}, 'name': 'Dev Builds',
{ 'description': 'Development builds of I2P',
'name': 'Dev Builds', 'icon': '/themes/console/images/script_gear.png',
'description': 'Development builds of I2P', 'url': 'http://bobthebuilder.i2p/'
'icon': '/themes/console/images/script_gear.png', }, {
'url': 'http://bobthebuilder.i2p/' 'name': 'Dev Forum',
}, 'description': 'Development forum',
{ 'icon': '/themes/console/images/group_gear.png',
'name': 'Dev Forum', 'url': 'http://zzz.i2p/'
'description': 'Development forum', }, {
'icon': '/themes/console/images/group_gear.png', 'name': 'echelon.i2p',
'url': 'http://zzz.i2p/' 'description': 'I2P Applications',
}, 'icon': '/themes/console/images/box_open.png',
{ 'url': 'http://echelon.i2p/'
'name': 'echelon.i2p', }, {
'description': 'I2P Applications', 'name': 'exchanged.i2p',
'icon': '/themes/console/images/box_open.png', 'description': 'Anonymous cryptocurrency exchange',
'url': 'http://echelon.i2p/' 'icon': '/themes/console/images/exchanged.png',
}, 'url': 'http://exchanged.i2p/'
{ }, {
'name': 'exchanged.i2p', 'name': 'I2P Bug Reports',
'description': 'Anonymous cryptocurrency exchange', 'description': 'Bug tracker',
'icon': '/themes/console/images/exchanged.png', 'icon': '/themes/console/images/bug.png',
'url': 'http://exchanged.i2p/' 'url': 'http://trac.i2p2.i2p/report/1'
}, }, {
{ 'name': 'I2P FAQ',
'name': 'I2P Bug Reports', 'description': 'Frequently Asked Questions',
'description': 'Bug tracker', 'icon': '/themes/console/images/question.png',
'icon': '/themes/console/images/bug.png', 'url': 'http://i2p-projekt.i2p/faq'
'url': 'http://trac.i2p2.i2p/report/1' }, {
}, 'name': 'I2P Forum',
{ 'description': 'Community forum',
'name': 'I2P FAQ', 'icon': '/themes/console/images/group.png',
'description': 'Frequently Asked Questions', 'url': 'http://i2pforum.i2p/'
'icon': '/themes/console/images/question.png', }, {
'url': 'http://i2p-projekt.i2p/faq' 'name': 'I2P Plugins',
}, 'description': 'Add-on directory',
{ 'icon': '/themes/console/images/info/plugin_link.png',
'name': 'I2P Forum', 'url': 'http://i2pwiki.i2p/index.php?title=Plugins'
'description': 'Community forum', }, {
'icon': '/themes/console/images/group.png', 'name': 'I2P Technical Docs',
'url': 'http://i2pforum.i2p/' 'description': 'Technical documentation',
}, 'icon': '/themes/console/images/education.png',
{ 'url': 'http://i2p-projekt.i2p/how'
'name': 'I2P Plugins', }, {
'description': 'Add-on directory', 'name': 'I2P Wiki',
'icon': '/themes/console/images/info/plugin_link.png', 'description': 'Anonymous wiki - share the knowledge',
'url': 'http://i2pwiki.i2p/index.php?title=Plugins' 'icon': '/themes/console/images/i2pwiki_logo.png',
}, 'url': 'http://i2pwiki.i2p/'
{ }, {
'name': 'I2P Technical Docs', 'name': 'Planet I2P',
'description': 'Technical documentation', 'description': 'I2P News',
'icon': '/themes/console/images/education.png', 'icon': '/themes/console/images/world.png',
'url': 'http://i2p-projekt.i2p/how' 'url': 'http://planet.i2p/'
}, }, {
{ 'name': 'PrivateBin',
'name': 'I2P Wiki', 'description': 'Encrypted I2P Pastebin',
'description': 'Anonymous wiki - share the knowledge', 'icon': '/themes/console/images/paste_plain.png',
'icon': '/themes/console/images/i2pwiki_logo.png', 'url': 'http://paste.crypthost.i2p/'
'url': 'http://i2pwiki.i2p/' }, {
}, 'name': 'Project Website',
{ 'description': 'I2P home page',
'name': 'Planet I2P', 'icon': '/themes/console/images/info_rhombus.png',
'description': 'I2P News', 'url': 'http://i2p-projekt.i2p/'
'icon': '/themes/console/images/world.png', }, {
'url': 'http://planet.i2p/' 'name': 'stats.i2p',
}, 'description': 'I2P Network Statistics',
{ 'icon': '/themes/console/images/chart_line.png',
'name': 'PrivateBin', 'url': 'http://stats.i2p/cgi-bin/dashboard.cgi'
'description': 'Encrypted I2P Pastebin', }, {
'icon': '/themes/console/images/paste_plain.png', 'name': 'The Tin Hat',
'url': 'http://paste.crypthost.i2p/' 'description': 'Privacy guides and tutorials',
}, 'icon': '/themes/console/images/thetinhat.png',
{ 'url': 'http://secure.thetinhat.i2p/'
'name': 'Project Website', }, {
'description': 'I2P home page', 'name': 'Trac Wiki',
'icon': '/themes/console/images/info_rhombus.png', 'description': '',
'url': 'http://i2p-projekt.i2p/' 'icon': '/themes/console/images/billiard_marker.png',
}, 'url': 'http://trac.i2p2.i2p/'
{ }]
'name': 'stats.i2p',
'description': 'I2P Network Statistics',
'icon': '/themes/console/images/chart_line.png',
'url': 'http://stats.i2p/cgi-bin/dashboard.cgi'
},
{
'name': 'The Tin Hat',
'description': 'Privacy guides and tutorials',
'icon': '/themes/console/images/thetinhat.png',
'url': 'http://secure.thetinhat.i2p/'
},
{
'name': 'Trac Wiki',
'description': '',
'icon': '/themes/console/images/billiard_marker.png',
'url': 'http://trac.i2p2.i2p/'
}
]
ADDITIONAL_FAVORITES = [ ADDITIONAL_FAVORITES = [
{ {
'name': 'Searx instance', 'name': 'Searx instance',

View File

@ -32,11 +32,10 @@ subsubmenu = [{
}, { }, {
'url': reverse_lazy('i2p:tunnels'), 'url': reverse_lazy('i2p:tunnels'),
'text': ugettext_lazy('Proxies') 'text': ugettext_lazy('Proxies')
}, }, {
{ 'url': reverse_lazy('i2p:torrents'),
'url': reverse_lazy('i2p:torrents'), 'text': ugettext_lazy('Anonymous torrents')
'text': ugettext_lazy('Anonymous torrents') }]
}]
class I2PAppView(AppView): class I2PAppView(AppView):

View File

@ -92,8 +92,7 @@ class IkiwikiApp(app_module.App):
"""Add an ikiwiki shortcut to frontpage.""" """Add an ikiwiki shortcut to frontpage."""
shortcut = frontpage.Shortcut('shortcut-ikiwiki-' + site, title, shortcut = frontpage.Shortcut('shortcut-ikiwiki-' + site, title,
icon=icon_filename, icon=icon_filename,
url='/ikiwiki/' + site, url='/ikiwiki/' + site, clients=clients)
clients=clients)
self.add(shortcut) self.add(shortcut)
return shortcut return shortcut

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Forms for configuring ikiwiki Forms for configuring ikiwiki
""" """
@ -25,14 +24,12 @@ from django.utils.translation import ugettext_lazy as _
class IkiwikiCreateForm(forms.Form): class IkiwikiCreateForm(forms.Form):
"""Form to create a wiki or blog.""" """Form to create a wiki or blog."""
site_type = forms.ChoiceField( site_type = forms.ChoiceField(label=_('Type'), choices=[('wiki', 'Wiki'),
label=_('Type'), ('blog', 'Blog')])
choices=[('wiki', 'Wiki'), ('blog', 'Blog')])
name = forms.CharField(label=_('Name')) name = forms.CharField(label=_('Name'))
admin_name = forms.CharField(label=_('Admin Account Name')) admin_name = forms.CharField(label=_('Admin Account Name'))
admin_password = forms.CharField( admin_password = forms.CharField(label=_('Admin Account Password'),
label=_('Admin Account Password'), widget=forms.PasswordInput())
widget=forms.PasswordInput())

View File

@ -28,8 +28,7 @@ clients = validate([{
}] }]
}]) }])
backup = validate_backup({ backup = validate_backup(
'data': { {'data': {
'directories': ['/var/lib/ikiwiki/', '/var/www/ikiwiki/'] 'directories': ['/var/lib/ikiwiki/', '/var/www/ikiwiki/']
} }})
})

View File

@ -63,10 +63,11 @@ class JSXCApp(app_module.App):
'jsxc:index', parent_url_name='apps') 'jsxc:index', parent_url_name='apps')
self.add(menu_item) self.add(menu_item)
shortcut = frontpage.Shortcut( shortcut = frontpage.Shortcut('shortcut-jsxc', name=name,
'shortcut-jsxc', name=name, short_description=short_description, short_description=short_description,
icon=icon_filename, icon=icon_filename,
url=reverse_lazy('jsxc:jsxc'), clients=clients) url=reverse_lazy('jsxc:jsxc'),
clients=clients)
self.add(shortcut) self.add(shortcut)
firewall = Firewall('firewall-jsxc', name, ports=['http', 'https'], firewall = Firewall('firewall-jsxc', name, ports=['http', 'https'],

View File

@ -326,9 +326,10 @@ class LetsEncrypt(app.FollowerComponent):
source_certificate_path, source_certificate_path,
private_key_path, certificate_path) private_key_path, certificate_path)
else: else:
self._copy_certificate( self._copy_certificate(source_private_key_path,
source_private_key_path, source_certificate_path, source_certificate_path,
self.private_key_path, self.certificate_path) self.private_key_path,
self.certificate_path)
def _copy_certificate(self, source_private_key_path, def _copy_certificate(self, source_private_key_path,
source_certificate_path, private_key_path, source_certificate_path, private_key_path,
@ -374,8 +375,8 @@ def on_certificate_event(event, domains, lineage):
certificate changes. certificate changes.
""" """
threading.Thread(target=on_certificate_event_sync, args=(event, domains, threading.Thread(target=on_certificate_event_sync,
lineage)).start() args=(event, domains, lineage)).start()
def on_certificate_event_sync(event, domains, lineage): def on_certificate_event_sync(event, domains, lineage):

View File

@ -108,9 +108,8 @@ class MatrixSynapseApp(app_module.App):
self.add(webserver) self.add(webserver)
letsencrypt = LetsEncrypt( letsencrypt = LetsEncrypt(
'letsencrypt-matrixsynapse', domains=get_domains, daemons=[ 'letsencrypt-matrixsynapse', domains=get_domains,
managed_services[0] daemons=[managed_services[0]], should_copy_certificates=True,
], should_copy_certificates=True,
private_key_path='/etc/matrix-synapse/homeserver.tls.key', private_key_path='/etc/matrix-synapse/homeserver.tls.key',
certificate_path='/etc/matrix-synapse/homeserver.tls.crt', certificate_path='/etc/matrix-synapse/homeserver.tls.crt',
user_owner='matrix-synapse', group_owner='nogroup', user_owner='matrix-synapse', group_owner='nogroup',

View File

@ -101,7 +101,6 @@ class MediaWikiApp(app_module.App):
class Shortcut(frontpage.Shortcut): class Shortcut(frontpage.Shortcut):
"""Frontpage shortcut for only logged users when in private mode.""" """Frontpage shortcut for only logged users when in private mode."""
def enable(self): def enable(self):
"""When enabled, check if MediaWiki is in private mode.""" """When enabled, check if MediaWiki is in private mode."""
super().enable() super().enable()

View File

@ -132,8 +132,8 @@ def diagnose():
def load_augeas(): def load_augeas():
"""Initialize Augeas.""" """Initialize Augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Php/lens', 'Php.lns') aug.set('/augeas/load/Php/lens', 'Php.lns')
aug.set('/augeas/load/Php/incl[last() + 1]', CONFIG_FILE) aug.set('/augeas/load/Php/incl[last() + 1]', CONFIG_FILE)
aug.load() aug.load()

View File

@ -28,9 +28,9 @@ class MinetestForm(AppForm):
"""Minetest configuration form""" """Minetest configuration form"""
max_players = forms.IntegerField( max_players = forms.IntegerField(
label=_('Maximum number of players'), required=True, min_value=1, label=_('Maximum number of players'), required=True, min_value=1,
max_value=100, help_text=_( max_value=100,
'You can change the maximum number of players playing ' help_text=_('You can change the maximum number of players playing '
'minetest at a single instance of time.')) 'minetest at a single instance of time.'))
creative_mode = forms.BooleanField( creative_mode = forms.BooleanField(
label=_('Enable creative mode'), required=False, label=_('Enable creative mode'), required=False,

View File

@ -80,10 +80,11 @@ class MLDonkeyApp(app_module.App):
parent_url_name='apps') parent_url_name='apps')
self.add(menu_item) self.add(menu_item)
shortcuts = frontpage.Shortcut( shortcuts = frontpage.Shortcut('shortcut-mldonkey', name,
'shortcut-mldonkey', name, short_description=short_description, short_description=short_description,
icon=icon_filename, url='/mldonkey/', login_required=True, icon=icon_filename, url='/mldonkey/',
clients=clients, allowed_groups=[group[0]]) login_required=True, clients=clients,
allowed_groups=[group[0]])
self.add(shortcuts) self.add(shortcuts)
firewall = Firewall('firewall-mldonkey', name, ports=['http', 'https'], firewall = Firewall('firewall-mldonkey', name, ports=['http', 'https'],

View File

@ -55,24 +55,18 @@ clients = validate([{
backup = validate_backup({ backup = validate_backup({
'config': { 'config': {
'files': [ 'files': [
'/var/lib/mldonkey/bittorrent.ini', '/var/lib/mldonkey/bittorrent.ini', '/var/lib/mldonkey/bt_dht.ini',
'/var/lib/mldonkey/bt_dht.ini',
'/var/lib/mldonkey/directconnect.ini', '/var/lib/mldonkey/directconnect.ini',
'/var/lib/mldonkey/donkey.ini', '/var/lib/mldonkey/donkey.ini', '/var/lib/mldonkey/downloads.ini',
'/var/lib/mldonkey/downloads.ini',
'/var/lib/mldonkey/files.ini', '/var/lib/mldonkey/files.ini',
'/var/lib/mldonkey/file_sources.ini', '/var/lib/mldonkey/file_sources.ini',
'/var/lib/mldonkey/fileTP.ini', '/var/lib/mldonkey/fileTP.ini', '/var/lib/mldonkey/friends.ini',
'/var/lib/mldonkey/friends.ini', '/var/lib/mldonkey/searches.ini', '/var/lib/mldonkey/servers.ini',
'/var/lib/mldonkey/searches.ini',
'/var/lib/mldonkey/servers.ini',
'/var/lib/mldonkey/shared_files.ini', '/var/lib/mldonkey/shared_files.ini',
'/var/lib/mldonkey/shared_files_new.ini', '/var/lib/mldonkey/shared_files_new.ini',
'/var/lib/mldonkey/statistics.ini', '/var/lib/mldonkey/statistics.ini',
'/var/lib/mldonkey/stats_bt.ini', '/var/lib/mldonkey/stats_bt.ini', '/var/lib/mldonkey/stats.ini',
'/var/lib/mldonkey/stats.ini', '/var/lib/mldonkey/stats_mod.ini', '/var/lib/mldonkey/users.ini'
'/var/lib/mldonkey/stats_mod.ini',
'/var/lib/mldonkey/users.ini'
] ]
}, },
'services': ['mldonkey-server'] 'services': ['mldonkey-server']

View File

@ -26,10 +26,10 @@ from plinth.views import AppView
urlpatterns = [ urlpatterns = [
url( url(
r'^apps/mldonkey/$', r'^apps/mldonkey/$',
AppView.as_view( AppView.as_view(app_id='mldonkey', name=mldonkey.name,
app_id='mldonkey', name=mldonkey.name, diagnostics_module_name='mldonkey',
diagnostics_module_name='mldonkey', description=mldonkey.description,
description=mldonkey.description, clients=mldonkey.clients, clients=mldonkey.clients,
manual_page=mldonkey.manual_page, show_status_block=True), manual_page=mldonkey.manual_page,
name='index'), show_status_block=True), name='index'),
] ]

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the monkeysphere module. URLs for the monkeysphere module.
""" """
@ -23,7 +22,6 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^sys/monkeysphere/$', views.index, name='index'), url(r'^sys/monkeysphere/$', views.index, name='index'),
url(r'^sys/monkeysphere/(?P<ssh_fingerprint>[0-9A-Za-z:+/]+)/import/$', url(r'^sys/monkeysphere/(?P<ssh_fingerprint>[0-9A-Za-z:+/]+)/import/$',

View File

@ -72,8 +72,4 @@ clients = validate([{
}] }]
}]) }])
backup = validate_backup({ backup = validate_backup({'data': {'directories': ['/var/lib/mumble-server']}})
'data': {
'directories': ['/var/lib/mumble-server']
}
})

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the name services module URLs for the name services module
""" """
@ -23,7 +22,6 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^sys/names/$', views.index, name='index'), url(r'^sys/names/$', views.index, name='index'),
] ]

View File

@ -84,10 +84,10 @@ def diagnose():
addresses = _get_interface_addresses(interfaces) addresses = _get_interface_addresses(interfaces)
for address in addresses: for address in addresses:
results.append( results.append(action_utils.diagnose_port_listening(
action_utils.diagnose_port_listening(53, 'tcp', address)) 53, 'tcp', address))
results.append( results.append(action_utils.diagnose_port_listening(
action_utils.diagnose_port_listening(53, 'udp', address)) 53, 'udp', address))
results.append(_diagnose_dnssec('4')) results.append(_diagnose_dnssec('4'))
results.append(_diagnose_dnssec('6')) results.append(_diagnose_dnssec('6'))

View File

@ -34,17 +34,15 @@ class ConnectionTypeSelectForm(forms.Form):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['connection_type'].widget.attrs.update({ self.fields['connection_type'].widget.attrs.update(
'autofocus': 'autofocus' {'autofocus': 'autofocus'})
})
class ConnectionForm(forms.Form): class ConnectionForm(forms.Form):
"""Base form to create/edit a connection.""" """Base form to create/edit a connection."""
name = forms.CharField(label=_('Connection Name')) name = forms.CharField(label=_('Connection Name'))
interface = forms.ChoiceField( interface = forms.ChoiceField(
label=_('Physical Interface'), label=_('Physical Interface'), choices=(),
choices=(),
help_text=_('The network device that this connection should be bound ' help_text=_('The network device that this connection should be bound '
'to.')) 'to.'))
zone = forms.ChoiceField( zone = forms.ChoiceField(
@ -52,90 +50,70 @@ class ConnectionForm(forms.Form):
help_text=_('The firewall zone will control which services are ' help_text=_('The firewall zone will control which services are '
'available over this interfaces. Select Internal only ' 'available over this interfaces. Select Internal only '
'for trusted networks.'), 'for trusted networks.'),
choices=[('external', _('External')), choices=[('external', _('External')), ('internal', _('Internal'))])
('internal', _('Internal'))])
ipv4_method = forms.ChoiceField( ipv4_method = forms.ChoiceField(
label=_('IPv4 Addressing Method'), label=_('IPv4 Addressing Method'), help_text=format_lazy(
help_text=format_lazy(
ugettext_lazy( ugettext_lazy(
'"Automatic" method will make {box_name} acquire ' '"Automatic" method will make {box_name} acquire '
'configuration from this network making it a client. "Shared" ' 'configuration from this network making it a client. "Shared" '
'method will make {box_name} act as a router, configure ' 'method will make {box_name} act as a router, configure '
'clients on this network and share its Internet connection.'), 'clients on this network and share its Internet connection.'),
box_name=ugettext_lazy(cfg.box_name)), box_name=ugettext_lazy(cfg.box_name)),
choices=[('auto', _('Automatic (DHCP)')), choices=[('auto', _('Automatic (DHCP)')), ('shared', _('Shared')),
('shared', _('Shared')), ('manual', _('Manual')), ('disabled', _('Disabled'))])
('manual', _('Manual')),
('disabled', _('Disabled'))])
ipv4_address = forms.CharField( ipv4_address = forms.CharField(
label=_('Address'), label=_('Address'), validators=[validators.validate_ipv4_address],
validators=[validators.validate_ipv4_address],
required=False) required=False)
ipv4_netmask = forms.CharField( ipv4_netmask = forms.CharField(
label=_('Netmask'), label=_('Netmask'),
help_text=_('Optional value. If left blank, a default netmask ' help_text=_('Optional value. If left blank, a default netmask '
'based on the address will be used.'), 'based on the address will be used.'),
validators=[validators.validate_ipv4_address], validators=[validators.validate_ipv4_address], required=False)
required=False)
ipv4_gateway = forms.CharField( ipv4_gateway = forms.CharField(
label=_('Gateway'), label=_('Gateway'), help_text=_('Optional value.'),
help_text=_('Optional value.'), validators=[validators.validate_ipv4_address], required=False)
validators=[validators.validate_ipv4_address],
required=False)
ipv4_dns = forms.CharField( ipv4_dns = forms.CharField(
label=_('DNS Server'), label=_('DNS Server'),
help_text=_('Optional value. If this value is given and IPv4 ' help_text=_('Optional value. If this value is given and IPv4 '
'addressing method is "Automatic", the DNS Servers ' 'addressing method is "Automatic", the DNS Servers '
'provided by a DHCP server will be ignored.'), 'provided by a DHCP server will be ignored.'),
validators=[validators.validate_ipv4_address], validators=[validators.validate_ipv4_address], required=False)
required=False)
ipv4_second_dns = forms.CharField( ipv4_second_dns = forms.CharField(
label=_('Second DNS Server'), label=_('Second DNS Server'),
help_text=_('Optional value. If this value is given and IPv4 ' help_text=_('Optional value. If this value is given and IPv4 '
'Addressing Method is "Automatic", the DNS Servers ' 'Addressing Method is "Automatic", the DNS Servers '
'provided by a DHCP server will be ignored.'), 'provided by a DHCP server will be ignored.'),
validators=[validators.validate_ipv4_address], validators=[validators.validate_ipv4_address], required=False)
required=False)
ipv6_method = forms.ChoiceField( ipv6_method = forms.ChoiceField(
label=_('IPv6 Addressing Method'), label=_('IPv6 Addressing Method'), help_text=format_lazy(
help_text=format_lazy(
ugettext_lazy( ugettext_lazy(
'"Automatic" methods will make {box_name} acquire ' '"Automatic" methods will make {box_name} acquire '
'configuration from this network making it a client.'), 'configuration from this network making it a client.'),
box_name=ugettext_lazy(cfg.box_name)), box_name=ugettext_lazy(cfg.box_name)),
choices=[('auto', _('Automatic')), choices=[('auto', _('Automatic')), ('dhcp', _('Automatic, DHCP only')),
('dhcp', _('Automatic, DHCP only')), ('manual', _('Manual')), ('ignore', _('Ignore'))])
('manual', _('Manual')),
('ignore', _('Ignore'))])
ipv6_address = forms.CharField( ipv6_address = forms.CharField(
label=_('Address'), label=_('Address'), validators=[validators.validate_ipv6_address],
validators=[validators.validate_ipv6_address],
required=False)
ipv6_prefix = forms.IntegerField(
label=_('Prefix'),
help_text=_('Value between 1 and 128.'),
min_value=1,
max_value=128,
required=False) required=False)
ipv6_prefix = forms.IntegerField(label=_('Prefix'),
help_text=_('Value between 1 and 128.'),
min_value=1, max_value=128,
required=False)
ipv6_gateway = forms.CharField( ipv6_gateway = forms.CharField(
label=_('Gateway'), label=_('Gateway'), help_text=_('Optional value.'),
help_text=_('Optional value.'), validators=[validators.validate_ipv6_address], required=False)
validators=[validators.validate_ipv6_address],
required=False)
ipv6_dns = forms.CharField( ipv6_dns = forms.CharField(
label=_('DNS Server'), label=_('DNS Server'),
help_text=_('Optional value. If this value is given and IPv6 ' help_text=_('Optional value. If this value is given and IPv6 '
'addressing method is "Automatic", the DNS Servers ' 'addressing method is "Automatic", the DNS Servers '
'provided by a DHCP server will be ignored.'), 'provided by a DHCP server will be ignored.'),
validators=[validators.validate_ipv6_address], validators=[validators.validate_ipv6_address], required=False)
required=False)
ipv6_second_dns = forms.CharField( ipv6_second_dns = forms.CharField(
label=_('Second DNS Server'), label=_('Second DNS Server'),
help_text=_('Optional value. If this value is given and IPv6 ' help_text=_('Optional value. If this value is given and IPv6 '
'Addressing Method is "Automatic", the DNS Servers ' 'Addressing Method is "Automatic", the DNS Servers '
'provided by a DHCP server will be ignored.'), 'provided by a DHCP server will be ignored.'),
validators=[validators.validate_ipv6_address], validators=[validators.validate_ipv6_address], required=False)
required=False)
@staticmethod @staticmethod
def _get_interface_choices(device_type): def _get_interface_choices(device_type):
@ -143,8 +121,8 @@ class ConnectionForm(forms.Form):
interfaces = network.get_interface_list(device_type) interfaces = network.get_interface_list(device_type)
choices = [('', _('-- select --'))] choices = [('', _('-- select --'))]
for interface, mac in interfaces.items(): for interface, mac in interfaces.items():
display_string = '{interface} ({mac})'.format(interface=interface, display_string = '{interface} ({mac})'.format(
mac=mac) interface=interface, mac=mac)
choices.append((interface, display_string)) choices.append((interface, display_string))
return choices return choices
@ -258,33 +236,29 @@ class PPPoEForm(EthernetForm):
class WifiForm(ConnectionForm): class WifiForm(ConnectionForm):
"""Form to create/edit a Wi-Fi connection.""" """Form to create/edit a Wi-Fi connection."""
field_order = ['name', 'interface', 'zone', 'ssid', 'mode', 'band', field_order = [
'channel', 'bssid', 'auth_mode', 'passphrase', 'name', 'interface', 'zone', 'ssid', 'mode', 'band', 'channel',
'ipv4_method', 'ipv4_address', 'ipv4_netmask', 'bssid', 'auth_mode', 'passphrase', 'ipv4_method', 'ipv4_address',
'ipv4_gateway', 'ipv4_dns', 'ipv4_second_dns', 'ipv4_netmask', 'ipv4_gateway', 'ipv4_dns', 'ipv4_second_dns',
'ipv6_method', 'ipv6_address', 'ipv6_prefix', 'ipv6_method', 'ipv6_address', 'ipv6_prefix', 'ipv6_gateway',
'ipv6_gateway', 'ipv6_dns', 'ipv6_second_dns'] 'ipv6_dns', 'ipv6_second_dns'
]
ssid = forms.CharField( ssid = forms.CharField(label=_('SSID'),
label=_('SSID'), help_text=_('The visible name of the network.'))
help_text=_('The visible name of the network.'))
mode = forms.ChoiceField( mode = forms.ChoiceField(
label=_('Mode'), label=_('Mode'), choices=[('infrastructure', _('Infrastructure')),
choices=[('infrastructure', _('Infrastructure')), ('ap', _('Access Point')),
('ap', _('Access Point')), ('adhoc', _('Ad-hoc'))])
('adhoc', _('Ad-hoc'))])
band = forms.ChoiceField( band = forms.ChoiceField(
label=_('Frequency Band'), label=_('Frequency Band'), choices=[('auto', _('Automatic')),
choices=[('auto', _('Automatic')), ('a', _('A (5 GHz)')),
('a', _('A (5 GHz)')), ('bg', _('B/G (2.4 GHz)'))])
('bg', _('B/G (2.4 GHz)'))])
channel = forms.IntegerField( channel = forms.IntegerField(
label=_('Channel'), label=_('Channel'),
help_text=_('Optional value. Wireless channel in the selected ' help_text=_('Optional value. Wireless channel in the selected '
'frequency band to restrict to. Blank or 0 value means ' 'frequency band to restrict to. Blank or 0 value means '
'automatic selection.'), 'automatic selection.'), min_value=0, max_value=255,
min_value=0,
max_value=255,
required=False) required=False)
bssid = forms.RegexField( bssid = forms.RegexField(
label=_('BSSID'), label=_('BSSID'),
@ -292,18 +266,15 @@ class WifiForm(ConnectionForm):
'When connecting to an access point, connect only if the ' 'When connecting to an access point, connect only if the '
'BSSID of the access point matches the one provided. ' 'BSSID of the access point matches the one provided. '
'Example: 00:11:22:aa:bb:cc.'), 'Example: 00:11:22:aa:bb:cc.'),
regex=r'^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$', regex=r'^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$', required=False)
required=False)
auth_mode = forms.ChoiceField( auth_mode = forms.ChoiceField(
label=_('Authentication Mode'), label=_('Authentication Mode'),
help_text=_('Select WPA if the wireless network is secured and \ help_text=_('Select WPA if the wireless network is secured and \
requires clients to have the password to connect.'), requires clients to have the password to connect.'),
choices=[('wpa', _('WPA')), choices=[('wpa', _('WPA')), ('open', _('Open'))])
('open', _('Open'))]) passphrase = forms.CharField(label=_('Passphrase'),
passphrase = forms.CharField( validators=[validators.MinLengthValidator(8)],
label=_('Passphrase'), required=False)
validators=[validators.MinLengthValidator(8)],
required=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""Initialize the form, populate interface choices.""" """Initialize the form, populate interface choices."""

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the Network module URLs for the Network module
""" """
@ -23,7 +22,6 @@ from django.conf.urls import url
from . import networks as views from . import networks as views
urlpatterns = [ urlpatterns = [
url(r'^sys/networks/$', views.index, name='index'), url(r'^sys/networks/$', views.index, name='index'),
url(r'^sys/networks/(?P<uuid>[\w.@+-]+)/show/$', views.show, name='show'), url(r'^sys/networks/(?P<uuid>[\w.@+-]+)/show/$', views.show, name='show'),
@ -38,9 +36,9 @@ urlpatterns = [
url(r'^sys/networks/add/ethernet/$', views.add_ethernet, url(r'^sys/networks/add/ethernet/$', views.add_ethernet,
name='add_ethernet'), name='add_ethernet'),
url(r'^sys/networks/add/pppoe/$', views.add_pppoe, name='add_pppoe'), url(r'^sys/networks/add/pppoe/$', views.add_pppoe, name='add_pppoe'),
url(r'^sys/networks/add/wifi/(?:(?P<ssid>[^/]+)/' url(
r'(?P<interface_name>[^/]+)/)?$', r'^sys/networks/add/wifi/(?:(?P<ssid>[^/]+)/'
views.add_wifi, name='add_wifi'), r'(?P<interface_name>[^/]+)/)?$', views.add_wifi, name='add_wifi'),
url(r'^sys/networks/(?P<uuid>[\w.@+-]+)/delete/$', views.delete, url(r'^sys/networks/(?P<uuid>[\w.@+-]+)/delete/$', views.delete,
name='delete'), name='delete'),
] ]

View File

@ -24,6 +24,5 @@ from django.utils.translation import ugettext_lazy as _
class OpenVpnForm(forms.Form): # pylint: disable=W0232 class OpenVpnForm(forms.Form): # pylint: disable=W0232
"""OpenVPN configuration form.""" """OpenVPN configuration form."""
enabled = forms.BooleanField( enabled = forms.BooleanField(label=_('Enable OpenVPN server'),
label=_('Enable OpenVPN server'), required=False)
required=False)

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the OpenVPN module. URLs for the OpenVPN module.
""" """
@ -24,7 +23,6 @@ from django.conf.urls import url
from plinth.utils import non_admin_view from plinth.utils import non_admin_view
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^apps/openvpn/$', views.index, name='index'), url(r'^apps/openvpn/$', views.index, name='index'),
url(r'^apps/openvpn/setup/$', views.setup, name='setup'), url(r'^apps/openvpn/setup/$', views.setup, name='setup'),

View File

@ -14,36 +14,42 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Test modules for Pagekite functions. Test modules for Pagekite functions.
""" """
from plinth.modules.pagekite import utils from plinth.modules.pagekite import utils
_tests = [ _tests = [
{ {
'line': 'https/8080:*.@kitename:localhost:8080:@kitesecret', 'line': 'https/8080:*.@kitename:localhost:8080:@kitesecret',
'params': {'kitename': '*.@kitename', 'backend_host': 'localhost', 'params': {
'secret': '@kitesecret', 'protocol': 'https/8080', 'kitename': '*.@kitename',
'backend_port': '8080'} 'backend_host': 'localhost',
'secret': '@kitesecret',
'protocol': 'https/8080',
'backend_port': '8080'
}
}, },
{ {
'line': 'https:*.@kitename:localhost:80:@kitesecret', 'line': 'https:*.@kitename:localhost:80:@kitesecret',
'params': {'protocol': 'https', 'params': {
'kitename': '*.@kitename', 'protocol': 'https',
'backend_port': '80', 'kitename': '*.@kitename',
'backend_host': 'localhost', 'backend_port': '80',
'secret': '@kitesecret'} 'backend_host': 'localhost',
'secret': '@kitesecret'
}
}, },
{ {
'line': 'raw/22:@kitename:localhost:22:@kitesecret', 'line': 'raw/22:@kitename:localhost:22:@kitesecret',
'params': {'protocol': 'raw/22', 'params': {
'kitename': '@kitename', 'protocol': 'raw/22',
'backend_port': '22', 'kitename': '@kitename',
'backend_host': 'localhost', 'backend_port': '22',
'secret': '@kitesecret'} 'backend_host': 'localhost',
'secret': '@kitesecret'
}
}, },
] ]

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the power module. URLs for the power module.
""" """
@ -23,7 +22,6 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^sys/power/$', views.index, name='index'), url(r'^sys/power/$', views.index, name='index'),
url(r'^sys/power/restart$', views.restart, name='restart'), url(r'^sys/power/restart$', views.restart, name='restart'),

View File

@ -110,7 +110,6 @@ class RadicaleApp(app_module.App):
class RadicaleWebserver(Webserver): class RadicaleWebserver(Webserver):
"""Webserver enable/disable behavior specific for radicale.""" """Webserver enable/disable behavior specific for radicale."""
@property @property
def web_name(self): def web_name(self):
"""Return web configuration name based on radicale version.""" """Return web configuration name based on radicale version."""
@ -127,7 +126,6 @@ class RadicaleWebserver(Webserver):
class RadicaleUwsgi(Uwsgi): class RadicaleUwsgi(Uwsgi):
"""uWSGI enable/disable behavior specific for radicale.""" """uWSGI enable/disable behavior specific for radicale."""
def is_enabled(self): def is_enabled(self):
"""Return whether the uWSGI configuration is enabled if version>=2.""" """Return whether the uWSGI configuration is enabled if version>=2."""
package_version = get_package_version() package_version = get_package_version()
@ -152,7 +150,6 @@ class RadicaleUwsgi(Uwsgi):
class RadicaleDaemon(Daemon): class RadicaleDaemon(Daemon):
"""Daemon enable/disable behavior specific for radicale.""" """Daemon enable/disable behavior specific for radicale."""
@staticmethod @staticmethod
def _is_old_radicale(): def _is_old_radicale():
"""Return whether radicale is less than version 2.""" """Return whether radicale is less than version 2."""
@ -251,8 +248,8 @@ def disable():
def load_augeas(): def load_augeas():
"""Prepares the augeas.""" """Prepares the augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
# INI file lens # INI file lens
aug.set('/augeas/load/Puppet/lens', 'Puppet.lns') aug.set('/augeas/load/Puppet/lens', 'Puppet.lns')

View File

@ -87,8 +87,7 @@ clients = validate([{
'name': 'evolution' 'name': 'evolution'
}] }]
}, { }, {
'name': 'name': _('Radicale'),
_('Radicale'),
'platforms': [{ 'platforms': [{
'type': 'web', 'type': 'web',
'url': '/radicale/' 'url': '/radicale/'

View File

@ -80,8 +80,7 @@ class RoundcubeApp(app_module.App):
shortcut = frontpage.Shortcut('shortcut-roundcube', name, shortcut = frontpage.Shortcut('shortcut-roundcube', name,
short_description=short_description, short_description=short_description,
icon=icon_filename, icon=icon_filename, url='/roundcube/',
url='/roundcube/',
clients=clients, login_required=True) clients=clients, login_required=True)
self.add(shortcut) self.add(shortcut)

View File

@ -29,7 +29,7 @@ from plinth.modules.apache.components import Uwsgi, Webserver
from plinth.modules.firewall.components import Firewall from plinth.modules.firewall.components import Firewall
from plinth.modules.users import register_group from plinth.modules.users import register_group
from .manifest import PUBLIC_ACCESS_SETTING_FILE, backup, clients # noqa, pylint: disable=unused-import from .manifest import PUBLIC_ACCESS_SETTING_FILE, backup, clients # noqa, pylint: disable=unused-import
clients = clients clients = clients
@ -99,7 +99,6 @@ class SearxApp(app_module.App):
class SearxWebserverAuth(Webserver): class SearxWebserverAuth(Webserver):
"""Component to handle Searx authentication webserver configuration.""" """Component to handle Searx authentication webserver configuration."""
def is_enabled(self): def is_enabled(self):
"""Return if configuration is enabled or public access is enabled.""" """Return if configuration is enabled or public access is enabled."""
return is_public_access_enabled() or super().is_enabled() return is_public_access_enabled() or super().is_enabled()

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
Forms for security module Forms for security module
""" """

View File

@ -20,8 +20,7 @@ Application manifest for security.
from plinth.modules.backups.api import validate as validate_backup from plinth.modules.backups.api import validate as validate_backup
backup = validate_backup({ backup = validate_backup(
'config': { {'config': {
'files': ['/etc/security/access.d/50freedombox.conf'] 'files': ['/etc/security/access.d/50freedombox.conf']
} }})
})

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
""" """
URLs for the security module URLs for the security module
""" """
@ -23,7 +22,6 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^sys/security/$', views.index, name='index'), url(r'^sys/security/$', views.index, name='index'),
url(r'^sys/security/report$', views.report, name='report'), url(r'^sys/security/report$', views.report, name='report'),

View File

@ -43,15 +43,11 @@ def index(request):
else: else:
form = SecurityForm(initial=status, prefix='security') form = SecurityForm(initial=status, prefix='security')
return TemplateResponse( return TemplateResponse(request, 'security.html', {
request, 'security.html', { 'name': _('Security'),
'name': 'manual_page': security.manual_page,
_('Security'), 'form': form,
'manual_page': })
security.manual_page,
'form':
form,
})
def get_status(request): def get_status(request):

View File

@ -39,7 +39,6 @@ METHODS = [('chacha20-ietf-poly1305',
class TrimmedCharField(forms.CharField): class TrimmedCharField(forms.CharField):
"""Trim the contents of a CharField""" """Trim the contents of a CharField"""
def clean(self, value): def clean(self, value):
"""Clean and validate the field value""" """Clean and validate the field value"""
if value: if value:
@ -50,12 +49,12 @@ class TrimmedCharField(forms.CharField):
class ShadowsocksForm(AppForm): class ShadowsocksForm(AppForm):
"""Shadowsocks configuration form""" """Shadowsocks configuration form"""
server = TrimmedCharField( server = TrimmedCharField(label=_('Server'),
label=_('Server'), help_text=_('Server hostname or IP address')) help_text=_('Server hostname or IP address'))
server_port = forms.IntegerField( server_port = forms.IntegerField(label=_('Server port'), min_value=0,
label=_('Server port'), min_value=0, max_value=65535, max_value=65535,
help_text=_('Server port number')) help_text=_('Server port number'))
password = forms.CharField( password = forms.CharField(
label=_('Password'), help_text=_('Password used to encrypt data. ' label=_('Password'), help_text=_('Password used to encrypt data. '

View File

@ -100,8 +100,8 @@ def setup(helper, old_version=None):
def load_augeas(): def load_augeas():
"""Initialize Augeas.""" """Initialize Augeas."""
aug = augeas.Augeas( aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
flags=augeas.Augeas.NO_LOAD + augeas.Augeas.NO_MODL_AUTOLOAD) augeas.Augeas.NO_MODL_AUTOLOAD)
# shell-script config file lens # shell-script config file lens
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns') aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')

View File

@ -38,9 +38,10 @@ class SnapshotForm(forms.Form):
choices=[('yes', 'Enabled'), ('no', 'Disabled')]) choices=[('yes', 'Enabled'), ('no', 'Disabled')])
enable_software_snapshots = forms.ChoiceField( enable_software_snapshots = forms.ChoiceField(
label=_('Software Installation Snapshots'), help_text=_( label=_('Software Installation Snapshots'),
'Enable or disable snapshots before and after software ' help_text=_('Enable or disable snapshots before and after software '
'installation'), choices=[('yes', 'Enabled'), ('no', 'Disabled')]) 'installation'), choices=[('yes', 'Enabled'),
('no', 'Disabled')])
hourly_limit = forms.IntegerField( hourly_limit = forms.IntegerField(
label=_('Hourly Snapshots Limit'), min_value=0, label=_('Hourly Snapshots Limit'), min_value=0,

Some files were not shown because too many files have changed in this diff Show More