mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
[enh] Add i18n \o/ 👏
This commit is contained in:
parent
8bdb79cfba
commit
24cbd03d47
19 changed files with 615 additions and 216 deletions
|
@ -33,6 +33,7 @@ import time
|
|||
import re
|
||||
import socket
|
||||
import urlparse
|
||||
import errno
|
||||
|
||||
from moulinette.helpers import win_msg, random_password, is_true, validate
|
||||
from moulinette.core import MoulinetteError
|
||||
|
@ -55,7 +56,7 @@ def app_listlists():
|
|||
if '.json' in filename:
|
||||
list_list.append(filename[:len(filename)-5])
|
||||
except OSError:
|
||||
raise MoulinetteError(1, _("No list found"))
|
||||
raise MoulinetteError(1, m18n.n('no_list_found'))
|
||||
|
||||
return { 'Lists' : list_list }
|
||||
|
||||
|
@ -77,12 +78,14 @@ def app_fetchlist(url=None, name=None):
|
|||
url = 'http://app.yunohost.org/list.json'
|
||||
name = 'yunohost'
|
||||
else:
|
||||
if name is None: raise MoulinetteError(22, _("You must indicate a name for your custom list"))
|
||||
if name is None:
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('custom_list_name_required'))
|
||||
|
||||
list_file = '%s/%s.json' % (repo_path, name)
|
||||
if os.system('wget "%s" -O "%s.tmp"' % (url, list_file)) != 0:
|
||||
os.remove('%s.tmp' % list_file)
|
||||
raise MoulinetteError(1, _("List server connection failed"))
|
||||
raise MoulinetteError(errno.EBADR, m18n.n('list_retrieve_error'))
|
||||
|
||||
# Rename fetched temp list
|
||||
os.rename('%s.tmp' % list_file, list_file)
|
||||
|
@ -90,7 +93,7 @@ def app_fetchlist(url=None, name=None):
|
|||
os.system("touch /etc/cron.d/yunohost-applist-%s" % name)
|
||||
os.system("echo '00 00 * * * root yunohost app fetchlist -u %s -n %s --no-ldap > /dev/null 2>&1' >/etc/cron.d/yunohost-applist-%s" % (url, name, name))
|
||||
|
||||
msignals.display(_("List successfully fetched"), 'success')
|
||||
msignals.display(m18n.n('list_fetched'), 'success')
|
||||
|
||||
|
||||
def app_removelist(name):
|
||||
|
@ -105,9 +108,9 @@ def app_removelist(name):
|
|||
os.remove('%s/%s.json' % (repo_path, name))
|
||||
os.remove("/etc/cron.d/yunohost-applist-%s" % name)
|
||||
except OSError:
|
||||
raise MoulinetteError(22, _("Unknown list"))
|
||||
raise MoulinetteError(errno.ENOENT, m18n.n('unknown_list'))
|
||||
|
||||
msignals.display(_("List successfully removed"), 'success')
|
||||
msignals.display(m18n.n('list_removed'), 'success')
|
||||
|
||||
|
||||
def app_list(offset=None, limit=None, filter=None, raw=False):
|
||||
|
@ -268,7 +271,7 @@ def app_upgrade(auth, app, url=None, file=None):
|
|||
try:
|
||||
app_list()
|
||||
except MoulinetteError:
|
||||
raise MoulinetteError(1, _("No app to upgrade"))
|
||||
raise MoulinetteError(errno.ENODATA, m18n.n('app_no_upgrade'))
|
||||
|
||||
upgraded_apps = []
|
||||
|
||||
|
@ -281,7 +284,8 @@ def app_upgrade(auth, app, url=None, file=None):
|
|||
for app_id in app:
|
||||
installed = _is_installed(app_id)
|
||||
if not installed:
|
||||
raise MoulinetteError(1, _("%s is not installed") % app_id)
|
||||
raise MoulinetteError(errno.ENOPKG,
|
||||
m18n.n('app_not_installed') % app_id)
|
||||
|
||||
if app_id in upgraded_apps:
|
||||
continue
|
||||
|
@ -299,7 +303,8 @@ def app_upgrade(auth, app, url=None, file=None):
|
|||
elif url:
|
||||
manifest = _fetch_app_from_git(url)
|
||||
elif 'lastUpdate' not in new_app_dict or 'git' not in new_app_dict:
|
||||
raise MoulinetteError(22, _("%s is a custom app, please provide an URL manually in order to upgrade it") % app_id)
|
||||
raise MoulinetteError(errno.EDESTADDRREQ,
|
||||
m18n.n('custom_app_url_required') % app_id)
|
||||
elif (new_app_dict['lastUpdate'] > current_app_dict['lastUpdate']) \
|
||||
or ('update_time' not in current_app_dict['settings'] \
|
||||
and (new_app_dict['lastUpdate'] > current_app_dict['settings']['install_time'])) \
|
||||
|
@ -311,7 +316,8 @@ def app_upgrade(auth, app, url=None, file=None):
|
|||
|
||||
# Check min version
|
||||
if 'min_version' in manifest and __version__ < manifest['min_version']:
|
||||
raise MoulinetteError(1, _("%s requires a more recent version of the moulinette") % app_id)
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('app_recent_version_required') % app_id)
|
||||
|
||||
app_setting_path = apps_setting_path +'/'+ app_id
|
||||
|
||||
|
@ -355,12 +361,12 @@ def app_upgrade(auth, app, url=None, file=None):
|
|||
|
||||
# So much win
|
||||
upgraded_apps.append(app_id)
|
||||
msignals.display(_("%s upgraded successfully") % app_id, 'success')
|
||||
msignals.display(m18n.n('app_upgraded') % app_id, 'success')
|
||||
|
||||
if not upgraded_apps:
|
||||
raise MoulinetteError(1, _("No app to upgrade"))
|
||||
raise MoulinetteError(errno.ENODATA, m18n.n('no_app_upgrade'))
|
||||
|
||||
msignals.display(_("Upgrade complete"), 'success')
|
||||
msignals.display(m18n.n('upgrade_complete'), 'success')
|
||||
|
||||
|
||||
def app_install(auth, app, label=None, args=None):
|
||||
|
@ -386,19 +392,21 @@ def app_install(auth, app, label=None, args=None):
|
|||
|
||||
# Check ID
|
||||
if 'id' not in manifest or '__' in manifest['id']:
|
||||
raise MoulinetteError(22, _("App id is invalid"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('app_id_invalid'))
|
||||
|
||||
app_id = manifest['id']
|
||||
|
||||
# Check min version
|
||||
if 'min_version' in manifest and __version__ < manifest['min_version']:
|
||||
raise MoulinetteError(1, _("%s requires a more recent version of the moulinette") % app_id)
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('app_recent_version_required') % app_id)
|
||||
|
||||
# Check if app can be forked
|
||||
instance_number = _installed_instance_number(app_id, last=True) + 1
|
||||
if instance_number > 1 :
|
||||
if 'multi_instance' not in manifest or not is_true(manifest['multi_instance']):
|
||||
raise MoulinetteError(1, _("App is already installed"))
|
||||
raise MoulinetteError(errno.EEXIST,
|
||||
m18n.n('app_already_installed') % app_id)
|
||||
|
||||
app_id_forked = app_id + '__' + str(instance_number)
|
||||
|
||||
|
@ -467,18 +475,18 @@ def app_install(auth, app, label=None, args=None):
|
|||
os.system('chown -R root: %s' % app_setting_path)
|
||||
os.system('chown -R admin: %s/scripts' % app_setting_path)
|
||||
app_ssowatconf(auth)
|
||||
msignals.display(_("Installation complete"), 'success')
|
||||
msignals.display(m18n.n('installation_complete'), 'success')
|
||||
else:
|
||||
#TODO: display script fail messages
|
||||
hook_remove(app_id)
|
||||
shutil.rmtree(app_setting_path)
|
||||
shutil.rmtree(app_tmp_folder)
|
||||
raise MoulinetteError(1, _("Installation failed"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('installation_failed'))
|
||||
except KeyboardInterrupt, EOFError:
|
||||
hook_remove(app_id)
|
||||
shutil.rmtree(app_setting_path)
|
||||
shutil.rmtree(app_tmp_folder)
|
||||
raise MoulinetteError(125, _("Interrupted"))
|
||||
raise MoulinetteError(errno.EINTR, m18n.g('operation_interrupted'))
|
||||
|
||||
|
||||
def app_remove(app):
|
||||
|
@ -492,7 +500,7 @@ def app_remove(app):
|
|||
from yunohost.hook import hook_exec, hook_remove
|
||||
|
||||
if not _is_installed(app):
|
||||
raise MoulinetteError(22, _("App is not installed"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('app_not_installed') % app)
|
||||
|
||||
app_setting_path = apps_setting_path + app
|
||||
|
||||
|
@ -512,7 +520,7 @@ def app_remove(app):
|
|||
shutil.rmtree('/tmp/yunohost_remove')
|
||||
hook_remove(app)
|
||||
app_ssowatconf()
|
||||
msignals.display(_("App removed: %s") % app, 'success')
|
||||
msignals.display(m18n.n('app_removed') % app, 'success')
|
||||
|
||||
|
||||
def app_addaccess(auth, apps, users):
|
||||
|
@ -536,7 +544,8 @@ def app_addaccess(auth, apps, users):
|
|||
|
||||
for app in apps:
|
||||
if not _is_installed(app):
|
||||
raise MoulinetteError(22, _("App is not installed"))
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('app_not_installed') % app)
|
||||
|
||||
with open(apps_setting_path + app +'/settings.yml') as f:
|
||||
app_settings = yaml.load(f)
|
||||
|
@ -589,7 +598,8 @@ def app_removeaccess(auth, apps, users):
|
|||
new_users = ''
|
||||
|
||||
if not _is_installed(app):
|
||||
raise MoulinetteError(22, _("App is not installed"))
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('app_not_installed') % app)
|
||||
|
||||
with open(apps_setting_path + app +'/settings.yml') as f:
|
||||
app_settings = yaml.load(f)
|
||||
|
@ -631,7 +641,8 @@ def app_clearaccess(auth, apps):
|
|||
|
||||
for app in apps:
|
||||
if not _is_installed(app):
|
||||
raise MoulinetteError(22, _("App is not installed"))
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('app_not_installed') % app)
|
||||
|
||||
with open(apps_setting_path + app +'/settings.yml') as f:
|
||||
app_settings = yaml.load(f)
|
||||
|
@ -654,7 +665,7 @@ def app_makedefault(app, domain=None):
|
|||
|
||||
"""
|
||||
if not _is_installed(app):
|
||||
raise MoulinetteError(22, _("App is not installed"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('app_not_installed') % app)
|
||||
|
||||
with open(apps_setting_path + app +'/settings.yml') as f:
|
||||
app_settings = yaml.load(f)
|
||||
|
@ -665,10 +676,11 @@ def app_makedefault(app, domain=None):
|
|||
if domain is None:
|
||||
domain = app_domain
|
||||
elif domain not in domain_list()['Domains']:
|
||||
raise MoulinetteError(22, _("Domain doesn't exists"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('domain_unknown'))
|
||||
|
||||
if '/' in app_map(raw=True)[domain]:
|
||||
raise MoulinetteError(1, _("An app is already installed on this location"))
|
||||
raise MoulinetteError(errno.EEXIST,
|
||||
m18n.n('app_location_already_used'))
|
||||
|
||||
try:
|
||||
with open('/etc/ssowat/conf.json.persistent') as json_conf:
|
||||
|
@ -686,7 +698,7 @@ def app_makedefault(app, domain=None):
|
|||
|
||||
os.system('chmod 644 /etc/ssowat/conf.json.persistent')
|
||||
|
||||
win_msg('SSOwat persistent configuration has been updated')
|
||||
msignals.display(m18n.n('ssowat_conf_updated'), 'success')
|
||||
|
||||
|
||||
|
||||
|
@ -780,10 +792,10 @@ def app_checkport(port):
|
|||
s.connect(("localhost", int(port)))
|
||||
s.close()
|
||||
except socket.error:
|
||||
msignals.display(_("Port available: %s") % str(port), 'success')
|
||||
msignals.display(m18n.n('port_available') % int(port), 'success')
|
||||
else:
|
||||
raise MoulinetteError(22, _("Port not available: %s") % str(port))
|
||||
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('port_unavailable') % int(port))
|
||||
|
||||
|
||||
def app_checkurl(auth, url, app=None):
|
||||
|
@ -815,14 +827,15 @@ def app_checkurl(auth, url, app=None):
|
|||
validate(r'^([a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)(\.[a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)*(\.[a-zA-Z]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)$', domain)
|
||||
|
||||
if domain not in domain_list(auth)['domains']:
|
||||
raise MoulinetteError(22, _("Domain doesn't exists"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('domain_unknown'))
|
||||
|
||||
if domain in apps_map:
|
||||
if path in apps_map[domain]:
|
||||
raise MoulinetteError(1, _("An app is already installed on this location"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('app_location_already_used'))
|
||||
for app_path, v in apps_map[domain].items():
|
||||
if app_path in path and app_path.count('/') < path.count('/'):
|
||||
raise MoulinetteError(1, _("Unable to install app at this location"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('app_location_install_failed'))
|
||||
|
||||
if app is not None:
|
||||
app_setting(app, 'domain', value=domain)
|
||||
|
@ -852,13 +865,13 @@ def app_initdb(user, password=None, db=None, sql=None):
|
|||
mysql_root_pwd = open('/etc/yunohost/mysql').read().rstrip()
|
||||
mysql_command = 'mysql -u root -p%s -e "CREATE DATABASE %s ; GRANT ALL PRIVILEGES ON %s.* TO \'%s\'@localhost IDENTIFIED BY \'%s\';"' % (mysql_root_pwd, db, db, user, password)
|
||||
if os.system(mysql_command) != 0:
|
||||
raise MoulinetteError(1, _("MySQL DB creation failed"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('mysql_db_creation_failed'))
|
||||
if sql is not None:
|
||||
if os.system('mysql -u %s -p%s %s < %s' % (user, password, db, sql)) != 0:
|
||||
raise MoulinetteError(1, _("MySQL DB init failed"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('mysql_db_init_failed'))
|
||||
|
||||
if not return_pwd:
|
||||
msignals.display(_("Database initiliazed"), 'success')
|
||||
msignals.display(m18n.n('mysql_db_initialized'), 'success')
|
||||
|
||||
|
||||
def app_ssowatconf(auth):
|
||||
|
@ -951,7 +964,7 @@ def app_ssowatconf(auth):
|
|||
with open('/etc/ssowat/conf.json', 'w+') as f:
|
||||
json.dump(conf_dict, f, sort_keys=True, indent=4)
|
||||
|
||||
msignals.display(_('SSOwat configuration generated'), 'success')
|
||||
msignals.display(m18n.n('ssowat_conf_generated'), 'success')
|
||||
|
||||
|
||||
def _extract_app_from_file(path, remove=False):
|
||||
|
@ -968,7 +981,7 @@ def _extract_app_from_file(path, remove=False):
|
|||
"""
|
||||
global app_tmp_folder
|
||||
|
||||
print(_('Extracting...'))
|
||||
msignals.display(m18n.n('extracting'))
|
||||
|
||||
if os.path.exists(app_tmp_folder): shutil.rmtree(app_tmp_folder)
|
||||
os.makedirs(app_tmp_folder)
|
||||
|
@ -988,7 +1001,7 @@ def _extract_app_from_file(path, remove=False):
|
|||
extract_result = 1
|
||||
|
||||
if extract_result != 0:
|
||||
raise MoulinetteError(22, _("Invalid install file"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('app_extraction_failed'))
|
||||
|
||||
try:
|
||||
if len(os.listdir(app_tmp_folder)) == 1:
|
||||
|
@ -998,9 +1011,9 @@ def _extract_app_from_file(path, remove=False):
|
|||
manifest = json.loads(str(json_manifest.read()))
|
||||
manifest['lastUpdate'] = int(time.time())
|
||||
except IOError:
|
||||
raise MoulinetteError(1, _("Invalid App file"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('app_install_files_invalid'))
|
||||
|
||||
print(_('OK'))
|
||||
msignals.display(m18n.n('done'))
|
||||
|
||||
return manifest
|
||||
|
||||
|
@ -1018,7 +1031,7 @@ def _fetch_app_from_git(app):
|
|||
"""
|
||||
global app_tmp_folder
|
||||
|
||||
print(_('Downloading...'))
|
||||
msignals.display(m18n.n('downloading'))
|
||||
|
||||
if ('@' in app) or ('http://' in app) or ('https://' in app):
|
||||
if "github.com" in app:
|
||||
|
@ -1036,7 +1049,7 @@ def _fetch_app_from_git(app):
|
|||
manifest = json.loads(str(json_manifest.read()))
|
||||
manifest['lastUpdate'] = int(time.time())
|
||||
except IOError:
|
||||
raise MoulinetteError(1, _("Invalid App manifest"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('app_manifest_invalid'))
|
||||
|
||||
else:
|
||||
app_dict = app_list(raw=True)
|
||||
|
@ -1046,7 +1059,7 @@ def _fetch_app_from_git(app):
|
|||
app_info['manifest']['lastUpdate'] = app_info['lastUpdate']
|
||||
manifest = app_info['manifest']
|
||||
else:
|
||||
raise MoulinetteError(22, _("App doesn't exists"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('app_unknown'))
|
||||
|
||||
if "github.com" in app_info['git']['url']:
|
||||
url = app_info['git']['url'].replace("git@github.com:", "https://github.com/")
|
||||
|
@ -1063,9 +1076,9 @@ def _fetch_app_from_git(app):
|
|||
git_result_2 = os.system('cd %s && git reset --hard %s' % (app_tmp_folder, str(app_info['git']['revision'])))
|
||||
|
||||
if not git_result == git_result_2 == 0:
|
||||
raise MoulinetteError(22, _("Sources fetching failed"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('app_sources_fetch_failed'))
|
||||
|
||||
print(_('OK'))
|
||||
msignals.display(m18n.n('done'))
|
||||
|
||||
return manifest
|
||||
|
||||
|
@ -1134,4 +1147,3 @@ def _is_installed(app):
|
|||
continue
|
||||
|
||||
return False
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import re
|
|||
import shutil
|
||||
import json
|
||||
import yaml
|
||||
import errno
|
||||
from urllib import urlopen
|
||||
|
||||
from moulinette.core import MoulinetteError
|
||||
|
@ -89,7 +90,7 @@ def domain_add(auth, domains, main=False, dyndns=False):
|
|||
# DynDNS domain
|
||||
if dyndns:
|
||||
if len(domain.split('.')) < 3:
|
||||
raise MoulinetteError(22, _("Invalid domain '%s' for DynDNS" % domain))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('domain_dyndns_invalid'))
|
||||
import requests
|
||||
from yunohost.dyndns import dyndns_subscribe
|
||||
|
||||
|
@ -98,10 +99,12 @@ def domain_add(auth, domains, main=False, dyndns=False):
|
|||
dyndomain = '.'.join(domain.split('.')[1:])
|
||||
if dyndomain in dyndomains:
|
||||
if os.path.exists('/etc/cron.d/yunohost-dyndns'):
|
||||
raise MoulinetteError(22, _("You already have a DynDNS domain"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('domain_dyndns_already_subscribed'))
|
||||
dyndns_subscribe(domain=domain)
|
||||
else:
|
||||
raise MoulinetteError(22, _("Unknown DynDNS domain '%s'" % dyndomain))
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('domain_dyndns_root_unknown'))
|
||||
|
||||
# Commands
|
||||
ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA'
|
||||
|
@ -131,12 +134,13 @@ def domain_add(auth, domains, main=False, dyndns=False):
|
|||
|
||||
for command in command_list:
|
||||
if os.system(command) != 0:
|
||||
raise MoulinetteError(17, _("An error occurred during certificate generation"))
|
||||
raise MoulinetteError(errno.EIO,
|
||||
m18n.n('domain_cert_gen_failed'))
|
||||
|
||||
try:
|
||||
auth.validate_uniqueness({ 'virtualdomain': domain })
|
||||
except MoulinetteError:
|
||||
raise MoulinetteError(17, _("Domain already created"))
|
||||
raise MoulinetteError(errno.EEXIST, m18n.n('domain_exists'))
|
||||
|
||||
|
||||
attr_dict['virtualdomain'] = domain
|
||||
|
@ -169,7 +173,8 @@ def domain_add(auth, domains, main=False, dyndns=False):
|
|||
os.system('chown bind /var/lib/bind/%s.zone' % domain)
|
||||
|
||||
else:
|
||||
raise MoulinetteError(17, _("Zone file already exists for %s") % domain)
|
||||
raise MoulinetteError(errno.EEXIST,
|
||||
m18n.n('domain_zone_exists'))
|
||||
|
||||
conf_lines = [
|
||||
'zone "%s" {' % domain,
|
||||
|
@ -228,12 +233,12 @@ def domain_add(auth, domains, main=False, dyndns=False):
|
|||
result.append(domain)
|
||||
continue
|
||||
else:
|
||||
raise MoulinetteError(169, _("An error occurred during domain creation"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('domain_creation_failed'))
|
||||
|
||||
|
||||
os.system('yunohost app ssowatconf > /dev/null 2>&1')
|
||||
|
||||
msignals.display(_("Domain(s) successfully created."), 'success')
|
||||
msignals.display(m18n.n('domain_created'), 'success')
|
||||
return { 'domains': result }
|
||||
|
||||
|
||||
|
@ -253,7 +258,7 @@ def domain_remove(auth, domains):
|
|||
|
||||
for domain in domains:
|
||||
if domain not in domains_list:
|
||||
raise MoulinetteError(22, _("Unknown domain '%s'") % domain)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('domain_unknown'))
|
||||
|
||||
# Check if apps are installed on the domain
|
||||
for app in os.listdir('/etc/yunohost/apps/'):
|
||||
|
@ -264,7 +269,8 @@ def domain_remove(auth, domains):
|
|||
continue
|
||||
else:
|
||||
if app_domain == domain:
|
||||
raise MoulinetteError(1, _("One or more apps are installed on this domain, please uninstall them before proceed to domain removal"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('domain_uninstall_app_first'))
|
||||
|
||||
if auth.remove('virtualdomain=' + domain + ',ou=domains'):
|
||||
try:
|
||||
|
@ -291,13 +297,12 @@ def domain_remove(auth, domains):
|
|||
result.append(domain)
|
||||
continue
|
||||
else:
|
||||
raise MoulinetteError(169, _("An error occurred during domain deletion"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('domain_deletion_failed'))
|
||||
|
||||
os.system('yunohost app ssowatconf > /dev/null 2>&1')
|
||||
os.system('service nginx reload')
|
||||
os.system('service bind9 reload')
|
||||
os.system('service metronome restart')
|
||||
|
||||
msignals.display(_("Domain(s) successfully deleted."), 'success')
|
||||
msignals.display(m18n.n('domain_deleted'), 'success')
|
||||
return { 'domains': result }
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import requests
|
|||
import json
|
||||
import glob
|
||||
import base64
|
||||
import errno
|
||||
|
||||
from moulinette.core import MoulinetteError
|
||||
|
||||
|
@ -49,7 +50,7 @@ def dyndns_subscribe(subscribe_host="dyndns.yunohost.org", domain=None, key=None
|
|||
|
||||
# Verify if domain is available
|
||||
if requests.get('http://%s/test/%s' % (subscribe_host, domain)).status_code != 200:
|
||||
raise MoulinetteError(17, _("DynDNS domain is already taken"))
|
||||
raise MoulinetteError(errno.EEXIST, m18n.n('dyndns_unavailable'))
|
||||
|
||||
if key is None:
|
||||
if len(glob.glob('/etc/yunohost/dyndns/*.key')) == 0:
|
||||
|
@ -67,9 +68,10 @@ def dyndns_subscribe(subscribe_host="dyndns.yunohost.org", domain=None, key=None
|
|||
if r.status_code != 201:
|
||||
try: error = json.loads(r.text)['error']
|
||||
except: error = "Server error"
|
||||
raise MoulinetteError(1, _("An error occurred during DynDNS registration: %s") % error)
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('dyndns_registration_failed') % error)
|
||||
|
||||
msignals.display(_("Subscribed to DynDNS."), 'success')
|
||||
msignals.display(m18n.n('dyndns_registered'), 'success')
|
||||
|
||||
dyndns_installcron()
|
||||
|
||||
|
@ -134,12 +136,13 @@ def dyndns_update(dyn_host="dynhost.yunohost.org", domain=None, key=None, ip=Non
|
|||
else:
|
||||
private_key_file = key
|
||||
if os.system('/usr/bin/nsupdate -k %s /etc/yunohost/dyndns/zone' % private_key_file) == 0:
|
||||
msignals.display(_("IP successfully updated."), 'success')
|
||||
msignals.display(m18n.n('dyndns_ip_updated'), 'success')
|
||||
with open('/etc/yunohost/dyndns/old_ip', 'w') as f:
|
||||
f.write(new_ip)
|
||||
else:
|
||||
os.system('rm /etc/yunohost/dyndns/old_ip > /dev/null 2>&1')
|
||||
raise MoulinetteError(1, _("An error occurred during DynDNS update"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('dyndns_ip_update_failed'))
|
||||
|
||||
|
||||
def dyndns_installcron():
|
||||
|
@ -151,7 +154,7 @@ def dyndns_installcron():
|
|||
with open('/etc/cron.d/yunohost-dyndns', 'w+') as f:
|
||||
f.write('*/2 * * * * root yunohost dyndns update >> /dev/null')
|
||||
|
||||
msignals.display(_("DynDNS cron installed."), 'success')
|
||||
msignals.display(m18n.n('dyndns_cron_installed'), 'success')
|
||||
|
||||
|
||||
def dyndns_removecron():
|
||||
|
@ -163,6 +166,6 @@ def dyndns_removecron():
|
|||
try:
|
||||
os.remove("/etc/cron.d/yunohost-dyndns")
|
||||
except:
|
||||
raise MoulinetteError(167,_("DynDNS cron was not installed"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('dyndns_cron_remove_failed'))
|
||||
|
||||
msignals.display(_("DynDNS cron removed."), 'success')
|
||||
msignals.display(m18n.n('dyndns_cron_removed'), 'success')
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
import os
|
||||
import sys
|
||||
import yaml
|
||||
import errno
|
||||
try:
|
||||
import miniupnpc
|
||||
except ImportError:
|
||||
|
@ -66,7 +67,7 @@ def firewall_allow(port=None, protocol='TCP', ipv6=False, no_upnp=False):
|
|||
if port not in firewall[ipv][protocol]:
|
||||
firewall[ipv][protocol].append(port)
|
||||
else:
|
||||
msignals.display(_("Port already openned: %d" % port), 'warning')
|
||||
msignals.display(m18n.n('port_already_opened') % port, 'warning')
|
||||
|
||||
with open('/etc/yunohost/firewall.yml', 'w') as f:
|
||||
yaml.safe_dump(firewall, f, default_flow_style=False)
|
||||
|
@ -102,7 +103,7 @@ def firewall_disallow(port=None, protocol='TCP', ipv6=False):
|
|||
if port in firewall[ipv][protocol]:
|
||||
firewall[ipv][protocol].remove(port)
|
||||
else:
|
||||
msignals.display(_("Port already closed: %d" % port), 'warning')
|
||||
msignals.display(m18n.n('port_already_closed') % port, 'warning')
|
||||
|
||||
with open('/etc/yunohost/firewall.yml', 'w') as f:
|
||||
yaml.safe_dump(firewall, f, default_flow_style=False)
|
||||
|
@ -140,7 +141,7 @@ def firewall_reload():
|
|||
|
||||
# IPv4
|
||||
if os.system("iptables -P INPUT ACCEPT") != 0:
|
||||
raise MoulinetteError(1, _("You cannot play with iptables here. You are either in a container or your kernel does not support it."))
|
||||
raise MoulinetteError(errno.ESRCH, m18n.n('iptables_unavailable'))
|
||||
if upnp:
|
||||
try:
|
||||
upnpc = miniupnpc.UPnP()
|
||||
|
@ -154,9 +155,9 @@ def firewall_reload():
|
|||
except: pass
|
||||
upnpc.addportmapping(port, protocol, upnpc.lanaddr, port, 'yunohost firewall : port %d' % port, '')
|
||||
else:
|
||||
raise MoulinetteError(1, _("No uPnP device found"))
|
||||
raise MoulinetteError(errno.ENXIO, m18n.n('upnp_dev_not_found'))
|
||||
except:
|
||||
msignals.display(_("An error occured during uPnP port openning"), 'warning')
|
||||
msignals.display(m18n.n('upnp_port_open_failed'), 'warning')
|
||||
|
||||
os.system("iptables -F")
|
||||
os.system("iptables -X")
|
||||
|
@ -196,7 +197,7 @@ def firewall_reload():
|
|||
os.system("ip6tables -P INPUT DROP")
|
||||
|
||||
os.system("service fail2ban restart")
|
||||
msignals.display(_("Firewall successfully reloaded"), 'success')
|
||||
msignals.display(m18n.n('firewall_reloaded'), 'success')
|
||||
|
||||
return firewall_list()
|
||||
|
||||
|
@ -209,7 +210,6 @@ def firewall_upnp(action=None):
|
|||
action -- enable/disable
|
||||
|
||||
"""
|
||||
|
||||
firewall = firewall_list(raw=True)
|
||||
|
||||
if action:
|
||||
|
@ -221,7 +221,7 @@ def firewall_upnp(action=None):
|
|||
with open('/etc/cron.d/yunohost-firewall', 'w+') as f:
|
||||
f.write('*/50 * * * * root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin yunohost firewall reload >>/dev/null')
|
||||
|
||||
msignals.display(_("uPnP successfully enabled"), 'success')
|
||||
msignals.display(m18n.n('upnp_enabled'), 'success')
|
||||
|
||||
if action == 'disable':
|
||||
firewall['uPnP']['enabled'] = False
|
||||
|
@ -242,7 +242,7 @@ def firewall_upnp(action=None):
|
|||
try: os.remove('/etc/cron.d/yunohost-firewall')
|
||||
except: pass
|
||||
|
||||
msignals.display(_("uPnP successfully disabled"), 'success')
|
||||
msignals.display(m18n.n('upnp_disabled'), 'success')
|
||||
|
||||
if action:
|
||||
os.system("cp /etc/yunohost/firewall.yml /etc/yunohost/firewall.yml.old")
|
||||
|
@ -260,7 +260,7 @@ def firewall_stop():
|
|||
"""
|
||||
|
||||
if os.system("iptables -P INPUT ACCEPT") != 0:
|
||||
raise MoulinetteError(1, _("You cannot play with iptables here. You are either in a container or your kernel does not support it."))
|
||||
raise MoulinetteError(errno.ESRCH, m18n.n('iptables_unavailable'))
|
||||
|
||||
os.system("iptables -F")
|
||||
os.system("iptables -X")
|
||||
|
|
|
@ -27,6 +27,7 @@ import os
|
|||
import sys
|
||||
import re
|
||||
import json
|
||||
import errno
|
||||
|
||||
from moulinette.helpers import colorize
|
||||
from moulinette.core import MoulinetteError
|
||||
|
@ -111,7 +112,7 @@ def hook_check(file):
|
|||
with open(file[:file.index('scripts/')] + 'manifest.json') as f:
|
||||
manifest = json.loads(str(f.read()))
|
||||
except:
|
||||
raise MoulinetteError(22, _("Invalid app package"))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('app_manifest_invalid'))
|
||||
|
||||
action = file[file.index('scripts/') + 8:]
|
||||
if 'arguments' in manifest and action in manifest['arguments']:
|
||||
|
@ -140,7 +141,9 @@ def hook_exec(file, args=None):
|
|||
for arg in required_args:
|
||||
if arg['name'] in args:
|
||||
if 'choices' in arg and args[arg['name']] not in arg['choices']:
|
||||
raise MoulinetteError(22, _("Invalid choice") + ': ' + args[arg['name']])
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('hook_choice_invalid')
|
||||
% args[arg['name']])
|
||||
arg_list.append(args[arg['name']])
|
||||
else:
|
||||
if os.isatty(1) and 'ask' in arg:
|
||||
|
@ -159,7 +162,9 @@ def hook_exec(file, args=None):
|
|||
elif 'default' in arg:
|
||||
arg_list.append(arg['default'])
|
||||
else:
|
||||
raise MoulinetteError(22, _("Missing argument : %s") % arg['name'])
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('hook_argument_missing')
|
||||
% arg['name'])
|
||||
|
||||
file_path = "./"
|
||||
if "/" in file and file[0:2] != file_path:
|
||||
|
|
127
lib/yunohost/locales/en.json
Normal file
127
lib/yunohost/locales/en.json
Normal file
|
@ -0,0 +1,127 @@
|
|||
{
|
||||
"yunohost" : "YunoHost",
|
||||
|
||||
"upgrade_complete" : "Upgrade complete",
|
||||
"installation_complete" : "Installation complete",
|
||||
"installation_failed" : "Installation failed",
|
||||
|
||||
"no_list_found" : "No list found",
|
||||
"custom_list_name_required" : "You must provide a name for your custom list",
|
||||
"list_retrieve_error" : "Unable to retrieve the remote list",
|
||||
"list_feteched" : "List successfully fetched",
|
||||
"list_unknown" : "Unknown list",
|
||||
"list_removed" : "List successfully removed",
|
||||
"app_unknown" : "Unknown app",
|
||||
"app_no_upgrade" : "No app to upgrade",
|
||||
"app_not_installed" : "%s is not installed",
|
||||
"custom_app_url_required" : "You must provide an URL to upgrade your custom app %s",
|
||||
"app_recent_version_required" : "%s requires a more recent version of the moulinette",
|
||||
"app_upgraded" : "%s successfully upgraded",
|
||||
"app_id_invalid" : "Invalid app id",
|
||||
"app_already_installed" : "%s is already installed",
|
||||
"app_removed" : "%s successfully removed",
|
||||
"app_location_already_used" : "An app is already installed on this location",
|
||||
"app_location_install_failed" : "Unable to install the app on this location",
|
||||
"app_extraction_failed" : "Unable to extract installation files",
|
||||
"app_install_files_invalid" : "Invalid installation files",
|
||||
"app_manifest_invalid" : "Invalid app manifest",
|
||||
"app_sources_fetch_failed" : "Unable to fetch sources files",
|
||||
"ssowat_conf_updated" : "SSOwat persistent configuration successfully updated",
|
||||
"ssowat_conf_generated" : "SSOwat configuration successfully generated",
|
||||
"mysql_db_creation_failed" : "MySQL database creation failed",
|
||||
"mysql_db_init_failed" : "MySQL database init failed",
|
||||
"mysql_db_initialized" : "MySQL database successfully initialized",
|
||||
"extracting" : "Extracting...",
|
||||
"downloading" : "Downloading...",
|
||||
"done" : "Done.",
|
||||
|
||||
"domain_unknown" : "Unknown domain",
|
||||
"domain_dyndns_invalid" : "Invalid domain to use with DynDNS",
|
||||
"domain_dyndns_already_subscribed" : "You already have subscribed to a DynDNS domain",
|
||||
"domain_dyndns_root_unknown" : "Unknown DynDNS root domain",
|
||||
"domain_cert_gen_failed" : "Unable to generate certificate",
|
||||
"domain_exists" : "Domain already exists",
|
||||
"domain_zone_exists" : "Zone file already exists",
|
||||
"domain_creation_failed" : "Unable to create domain",
|
||||
"domain_created" : "Domain successfully created",
|
||||
"domain_uninstall_app_first" : "One or more apps are installed on this domain. Please uninstall them before proceed to domain removal.",
|
||||
"domain_deletion_failed" : "Unable to delete domain",
|
||||
"domain_deleted" : "Domain successfully deleted",
|
||||
|
||||
"dyndns_unavailable" : "Unavailable DynDNS subdomain",
|
||||
"dyndns_registration_failed" : "Unable to register DynDNS domain: %s",
|
||||
"dyndns_registered" : "DynDNS domain successfully registered",
|
||||
"dyndns_ip_update_failed" : "Unable to update IP address on DynDNS",
|
||||
"dyndns_ip_updated" : "IP address successfully updated on DynDNS",
|
||||
"dyndns_cron_installed" : "DynDNS cron job successfully installed",
|
||||
"dyndns_cron_remove_failed" : "Unable to remove DynDNS cron job",
|
||||
"dyndns_cron_removed" : "DynDNS cron job successfully removed",
|
||||
|
||||
"port_available" : "Port %d is available",
|
||||
"port_unavailable" : "Port %d is not available",
|
||||
"port_already_opened" : "Port %d is already opened",
|
||||
"port_already_closed" : "Port %d is already closed",
|
||||
"iptables_unavailable" : "You cannot play with iptables here. You are either in a container or your kernel does not support it.",
|
||||
"upnp_dev_not_found" : "No uPnP device found",
|
||||
"upnp_port_open_failed" : "Unable to open uPnP ports",
|
||||
"upnp_enabled" : "uPnP successfully enabled",
|
||||
"upnp_disabled" : "uPnP successfully disabled",
|
||||
"firewall_reloaded" : "Firewall successfully reloaded",
|
||||
|
||||
"hook_choice_invalid" : "Invalid choice '%s'",
|
||||
"hook_argument_missing" : "Missing argument '%s'",
|
||||
|
||||
"mountpoint_unknown" : "Unknown mountpoint",
|
||||
"unit_unknown" : "Unknown unit '%s'",
|
||||
"monitor_period_invalid" : "Invalid time period",
|
||||
"monitor_stats_no_update" : "No monitoring statistics to update",
|
||||
"monitor_stats_file_not_found" : "Statistics file not found",
|
||||
"monitor_stats_period_unavailable" : "No available statistics for the period",
|
||||
"monitor_enabled" : "Server monitoring successfully enabled",
|
||||
"monitor_disabled" : "Server monitoring successfully disabled",
|
||||
"monitor_not_enabled" : "Server monitoring is not enabled",
|
||||
"monitor_glances_con_failed" : "Unable to connect to Glances server",
|
||||
|
||||
"service_unknown" : "Unknown service '%s'",
|
||||
"service_start_failed" : "Unable to start service '%s'",
|
||||
"service_already_started" : "Service '%s' is already started",
|
||||
"service_started" : "Service '%s' successfully started",
|
||||
"service_stop_failed" : "Unable to stop service '%s'",
|
||||
"service_already_stopped" : "Service '%s' is already stopped",
|
||||
"service_stopped" : "Service '%s' successfully stopped",
|
||||
"service_enable_failed" : "Unable to enable service '%s'",
|
||||
"service_enabled" : "Service '%s' successfully enabled",
|
||||
"service_disable_failed" : "Unable to disable service '%s'",
|
||||
"service_disabled" : "Service '%s' successfully disabled",
|
||||
"service_status_failed" : "Unable to determine status of service '%s'",
|
||||
"service_no_log" : "No log to display for service '%s'",
|
||||
"service_cmd_exec_failed" : "Unable to execute command '%s'",
|
||||
|
||||
"ldap_initialized" : "LDAP successfully initialized",
|
||||
"password_too_short" : "Password is too short",
|
||||
"admin_password_change_failed" : "Unable to change password",
|
||||
"admin_password_changed" : "Administration password successfully changed",
|
||||
"maindomain_change_failed" : "Unable to change main domain",
|
||||
"maindomain_changed" : "Main domain successfully changed",
|
||||
"yunohost_installing" : "Installing YunoHost...",
|
||||
"yunohost_already_installed" : "YunoHost is already installed",
|
||||
"yunohost_ca_creation_failed" : "Unable to create certificate authority",
|
||||
"yunohost_configured" : "YunoHost successfully configured",
|
||||
"update_cache_failed" : "Unable to update APT cache",
|
||||
"system_no_upgrade" : "There is no packages to upgrade",
|
||||
"system_upgraded" : "System successfully upgraded",
|
||||
|
||||
"field_invalid" : "Invalid field '%s'",
|
||||
"mail_domain_unknown" : "Unknown mail address domain '%s'",
|
||||
"mail_alias_remove_failed" : "Unable to remove mail alias '%s'",
|
||||
"mail_forward_remove_failed" : "Unable to remove mail forward '%s'",
|
||||
"user_unknown" : "Unknown user",
|
||||
"user_creation_failed" : "Unable to create user",
|
||||
"user_created" : "User successfully created",
|
||||
"user_deletion_failed" : "Unable to delete user",
|
||||
"user_deleted" : "User successfully deleted",
|
||||
"user_update_failed" : "Unable to update user",
|
||||
"user_updated" : "User successfully updated",
|
||||
"user_info_failed" : "Unable to retrieve user information"
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ import calendar
|
|||
import subprocess
|
||||
import xmlrpclib
|
||||
import os.path
|
||||
import errno
|
||||
import cPickle as pickle
|
||||
from urllib import urlopen
|
||||
from datetime import datetime, timedelta
|
||||
|
@ -74,7 +75,7 @@ def monitor_disk(units=None, mountpoint=None, human_readable=False):
|
|||
result_dname = dn
|
||||
if len(devices) == 0:
|
||||
if mountpoint is not None:
|
||||
raise MoulinetteError(1, _("Unknown mountpoint '%s'") % mountpoint)
|
||||
raise MoulinetteError(errno.ENODEV, m18n.n('mountpoint_unknown'))
|
||||
return result
|
||||
|
||||
# Retrieve monitoring for unit(s)
|
||||
|
@ -131,7 +132,7 @@ def monitor_disk(units=None, mountpoint=None, human_readable=False):
|
|||
for dname in devices_names:
|
||||
_set(dname, 'not-available')
|
||||
else:
|
||||
raise MoulinetteError(1, _("Unknown unit '%s'") % u)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown') % u)
|
||||
|
||||
if result_dname is not None:
|
||||
return result[result_dname]
|
||||
|
@ -203,7 +204,7 @@ def monitor_network(units=None, human_readable=False):
|
|||
'gateway': gateway
|
||||
}
|
||||
else:
|
||||
raise MoulinetteError(1, _("Unknown unit '%s'") % u)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown') % u)
|
||||
|
||||
if len(units) == 1:
|
||||
return result[units[0]]
|
||||
|
@ -253,7 +254,7 @@ def monitor_system(units=None, human_readable=False):
|
|||
elif u == 'infos':
|
||||
result[u] = json.loads(glances.getSystem())
|
||||
else:
|
||||
raise MoulinetteError(1, _("Unknown unit '%s'") % u)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('unit_unknown') % u)
|
||||
|
||||
if len(units) == 1 and type(result[units[0]]) is not str:
|
||||
return result[units[0]]
|
||||
|
@ -269,7 +270,7 @@ def monitor_update_stats(period):
|
|||
|
||||
"""
|
||||
if period not in ['day', 'week', 'month']:
|
||||
raise MoulinetteError(22, _("Invalid period"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('monitor_period_invalid'))
|
||||
|
||||
stats = _retrieve_stats(period)
|
||||
if not stats:
|
||||
|
@ -287,7 +288,7 @@ def monitor_update_stats(period):
|
|||
else:
|
||||
monitor = _monitor_all(p, 0)
|
||||
if not monitor:
|
||||
raise MoulinetteError(1, _("No monitoring statistics to update"))
|
||||
raise MoulinetteError(errno.ENODATA, m18n.n('monitor_stats_no_update'))
|
||||
|
||||
stats['timestamp'].append(time.time())
|
||||
|
||||
|
@ -352,13 +353,15 @@ def monitor_show_stats(period, date=None):
|
|||
|
||||
"""
|
||||
if period not in ['day', 'week', 'month']:
|
||||
raise MoulinetteError(22, _("Invalid period"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('monitor_period_invalid'))
|
||||
|
||||
result = _retrieve_stats(period, date)
|
||||
if result is False:
|
||||
raise MoulinetteError(167, _("Stats file not found"))
|
||||
raise MoulinetteError(errno.ENOENT,
|
||||
m18n.n('monitor_stats_file_not_found'))
|
||||
elif result is None:
|
||||
raise MoulinetteError(1, _("No available stats for the given period"))
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('monitor_stats_period_unavailable'))
|
||||
return result
|
||||
|
||||
|
||||
|
@ -389,7 +392,7 @@ def monitor_enable(no_stats=False):
|
|||
os.system("touch %s" % crontab_path)
|
||||
os.system("echo '%s' >%s" % (rules, crontab_path))
|
||||
|
||||
msignals.display(_("Server monitoring successfully enabled."), 'success')
|
||||
msignals.display(m18n.n('monitor_enabled'), 'success')
|
||||
|
||||
|
||||
def monitor_disable():
|
||||
|
@ -407,7 +410,7 @@ def monitor_disable():
|
|||
try:
|
||||
service_disable('glances')
|
||||
except MoulinetteError as e:
|
||||
msignals.display('%s.' % e.strerror, 'warning')
|
||||
msignals.display(e.strerror, 'warning')
|
||||
|
||||
# Remove crontab
|
||||
try:
|
||||
|
@ -415,7 +418,7 @@ def monitor_disable():
|
|||
except:
|
||||
pass
|
||||
|
||||
msignals.display(_("Server monitoring successfully disabled."), 'success')
|
||||
msignals.display(m18n.n('monitor_disabled'), 'success')
|
||||
|
||||
|
||||
def _get_glances_api():
|
||||
|
@ -434,8 +437,8 @@ def _get_glances_api():
|
|||
from yunohost.service import service_status
|
||||
|
||||
if service_status('glances')['status'] != 'running':
|
||||
raise MoulinetteError(1, _("Monitoring is disabled"))
|
||||
raise MoulinetteError(1, _("Connection to Glances server failed"))
|
||||
raise MoulinetteError(errno.EPERM, m18n.n('monitor_not_enabled'))
|
||||
raise MoulinetteError(errno.EIO, m18n.n('monitor_glances_con_failed'))
|
||||
|
||||
|
||||
def _extract_inet(string, skip_netmask=False, skip_loopback=True):
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
import yaml
|
||||
import glob
|
||||
import subprocess
|
||||
import errno
|
||||
import os.path
|
||||
|
||||
from moulinette.core import MoulinetteError
|
||||
|
@ -43,11 +44,12 @@ def service_start(names):
|
|||
names = [names]
|
||||
for name in names:
|
||||
if _run_service_command('start', name):
|
||||
msignals.display(_("Service '%s' successfully started.") % name, 'success')
|
||||
msignals.display(m18n.n('service_started') % name, 'success')
|
||||
else:
|
||||
if service_status(name)['status'] != 'running':
|
||||
raise MoulinetteError(1, _("Starting of service '%s' failed") % name)
|
||||
msignals.display(_("Service '%s' already started.") % name)
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('service_start_failed') % name)
|
||||
msignals.display(m18n.n('service_already_started') % name)
|
||||
|
||||
|
||||
def service_stop(names):
|
||||
|
@ -62,11 +64,12 @@ def service_stop(names):
|
|||
names = [names]
|
||||
for name in names:
|
||||
if _run_service_command('stop', name):
|
||||
msignals.display(_("Service '%s' successfully stopped.") % name, 'success')
|
||||
msignals.display(m18n.n('service_stopped') % name, 'success')
|
||||
else:
|
||||
if service_status(name)['status'] != 'inactive':
|
||||
raise MoulinetteError(1, _("Stopping of service '%s' failed") % name)
|
||||
msignals.display(_("Service '%s' already stopped.") % name)
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('service_stop_failed') % name)
|
||||
msignals.display(m18n.n('service_already_stopped') % name)
|
||||
|
||||
|
||||
def service_enable(names):
|
||||
|
@ -81,9 +84,10 @@ def service_enable(names):
|
|||
names = [names]
|
||||
for name in names:
|
||||
if _run_service_command('enable', name):
|
||||
msignals.display(_("Service '%s' successfully enabled.") % name, 'success')
|
||||
msignals.display(m18n.n('service_enabled') % name, 'success')
|
||||
else:
|
||||
raise MoulinetteError(1, _("Enabling of service '%s' failed") % name)
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('service_enable_failed') % name)
|
||||
|
||||
|
||||
def service_disable(names):
|
||||
|
@ -98,9 +102,10 @@ def service_disable(names):
|
|||
names = [names]
|
||||
for name in names:
|
||||
if _run_service_command('disable', name):
|
||||
msignals.display(_("Service '%s' successfully disabled.") % name, 'success')
|
||||
msignals.display(m18n.n('service_disabled') % name, 'success')
|
||||
else:
|
||||
raise MoulinetteError(1, _("Disabling of service '%s' failed") % name)
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('service_disable_failed') % name)
|
||||
|
||||
|
||||
def service_status(names=[]):
|
||||
|
@ -123,7 +128,8 @@ def service_status(names=[]):
|
|||
|
||||
for name in names:
|
||||
if check_names and name not in services.keys():
|
||||
raise MoulinetteError(1, _("Unknown service '%s'") % name)
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('service_unknown') % name)
|
||||
|
||||
status = None
|
||||
if services[name]['status'] == 'service':
|
||||
|
@ -145,8 +151,8 @@ def service_status(names=[]):
|
|||
result[name]['status'] = 'inactive'
|
||||
else:
|
||||
# TODO: Log output?
|
||||
msignals.display(_("Could not determine status of service '%s'.") % \
|
||||
name, 'warning')
|
||||
msignals.display(m18n.n('service_status_failed') % name,
|
||||
'warning')
|
||||
else:
|
||||
result[name]['status'] = 'running'
|
||||
|
||||
|
@ -169,14 +175,14 @@ def service_log(name, number=50):
|
|||
Log every log files of a service
|
||||
|
||||
Keyword argument:
|
||||
name -- Services name to log
|
||||
name -- Service name to log
|
||||
number -- Number of lines to display
|
||||
|
||||
"""
|
||||
services = _get_services()
|
||||
|
||||
if name not in services.keys():
|
||||
raise MoulinetteError(1, _("Unknown service '%s'") % service)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown') % name)
|
||||
|
||||
if 'log' in services[name]:
|
||||
log_list = services[name]['log']
|
||||
|
@ -191,7 +197,7 @@ def service_log(name, number=50):
|
|||
else:
|
||||
result[log_path] = _tail(log_path, int(number))
|
||||
else:
|
||||
raise MoulinetteError(1, _("Nothing to log for service '%s'") % name)
|
||||
raise MoulinetteError(errno.EPERM, m18n.n('service_no_log') % name)
|
||||
|
||||
return result
|
||||
|
||||
|
@ -206,7 +212,7 @@ def _run_service_command(action, service):
|
|||
|
||||
"""
|
||||
if service not in _get_services().keys():
|
||||
raise MoulinetteError(1, _("Unknown service '%s'") % service)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown') % name)
|
||||
|
||||
cmd = None
|
||||
if action in ['start', 'stop']:
|
||||
|
@ -215,14 +221,14 @@ def _run_service_command(action, service):
|
|||
arg = 'defaults' if action == 'enable' else 'remove'
|
||||
cmd = 'update-rc.d %s %s' % (service, arg)
|
||||
else:
|
||||
raise MoulinetteError(1, _("Unknown action '%s'") % action)
|
||||
raise ValueError("Unknown action '%s'" % action)
|
||||
|
||||
try:
|
||||
ret = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# TODO: Log output?
|
||||
msignals.display(_("Execution of command '%s' failed.") % \
|
||||
' '.join(e.cmd), 'warning')
|
||||
msignals.display(m18n.n('service_cmd_exec_failed') % ' '.join(e.cmd),
|
||||
'warning')
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import re
|
|||
import getpass
|
||||
import requests
|
||||
import json
|
||||
import errno
|
||||
import apt
|
||||
import apt.progress
|
||||
|
||||
|
@ -69,7 +70,7 @@ def tools_ldapinit(auth):
|
|||
|
||||
auth.update('cn=admin', admin_dict)
|
||||
|
||||
msignals.display(_("LDAP has been successfully initialized"), 'success')
|
||||
msignals.display(m18n.n('ldap_ initialized'), 'success')
|
||||
|
||||
|
||||
def tools_adminpw(old_password, new_password):
|
||||
|
@ -83,7 +84,7 @@ def tools_adminpw(old_password, new_password):
|
|||
"""
|
||||
# Validate password length
|
||||
if len(new_password) < 4:
|
||||
raise MoulinetteError(22, _("Password is too short"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('password_too_short'))
|
||||
|
||||
old_password.replace('"', '\\"')
|
||||
old_password.replace('&', '\\&')
|
||||
|
@ -92,9 +93,10 @@ def tools_adminpw(old_password, new_password):
|
|||
result = os.system('ldappasswd -h localhost -D cn=admin,dc=yunohost,dc=org -w "%s" -a "%s" -s "%s"' % (old_password, old_password, new_password))
|
||||
|
||||
if result == 0:
|
||||
msignals.display(_("Admin password has been changed"), 'success')
|
||||
msignals.display(m18n.n('admin_password_changed'), 'success')
|
||||
else:
|
||||
raise MoulinetteError(22, _("Invalid password"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('admin_password_change_failed'))
|
||||
|
||||
|
||||
def tools_maindomain(auth, old_domain=None, new_domain=None, dyndns=False):
|
||||
|
@ -165,7 +167,8 @@ def tools_maindomain(auth, old_domain=None, new_domain=None, dyndns=False):
|
|||
|
||||
for command in command_list:
|
||||
if os.system(command) != 0:
|
||||
raise MoulinetteError(17, _("There were a problem during domain changing"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('maindomain_change_failed'))
|
||||
|
||||
if dyndns: dyndns_subscribe(domain=new_domain)
|
||||
elif len(new_domain.split('.')) >= 3:
|
||||
|
@ -175,7 +178,7 @@ def tools_maindomain(auth, old_domain=None, new_domain=None, dyndns=False):
|
|||
if dyndomain in dyndomains:
|
||||
dyndns_subscribe(domain=new_domain)
|
||||
|
||||
msignals.display(_("Main domain has been successfully changed"), 'success')
|
||||
msignals.display(m18n.n('maindomain_changed'), 'success')
|
||||
|
||||
|
||||
def tools_postinstall(domain, password, dyndns=False):
|
||||
|
@ -194,9 +197,9 @@ def tools_postinstall(domain, password, dyndns=False):
|
|||
try:
|
||||
with open('/etc/yunohost/installed') as f: pass
|
||||
except IOError:
|
||||
print('Installing YunoHost')
|
||||
msignals.display(m18n.n('yunohost_installing'))
|
||||
else:
|
||||
raise MoulinetteError(17, _("YunoHost is already installed"))
|
||||
raise MoulinetteError(errno.EPERM, m18n.n('yunohost_already_installed'))
|
||||
|
||||
if len(domain.split('.')) >= 3:
|
||||
r = requests.get('http://dyndns.yunohost.org/domains')
|
||||
|
@ -206,7 +209,8 @@ def tools_postinstall(domain, password, dyndns=False):
|
|||
if requests.get('http://dyndns.yunohost.org/test/%s' % domain).status_code == 200:
|
||||
dyndns=True
|
||||
else:
|
||||
raise MoulinetteError(17, _("Domain is already taken"))
|
||||
raise MoulinetteError(errno.EEXIST,
|
||||
m18n.n('dyndns_unavailable'))
|
||||
|
||||
# Create required folders
|
||||
folders_to_create = [
|
||||
|
@ -257,7 +261,8 @@ def tools_postinstall(domain, password, dyndns=False):
|
|||
|
||||
for command in command_list:
|
||||
if os.system(command) != 0:
|
||||
raise MoulinetteError(17, _("There were a problem during CA creation"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
m18n.n('yunohost_ca_creation_failed'))
|
||||
|
||||
# Initialize YunoHost LDAP base
|
||||
tools_ldapinit(auth)
|
||||
|
@ -277,7 +282,7 @@ def tools_postinstall(domain, password, dyndns=False):
|
|||
os.system('touch /etc/yunohost/installed')
|
||||
os.system('service yunohost-api restart &')
|
||||
|
||||
msignals.display(_("YunoHost has been successfully configured"), 'success')
|
||||
msignals.display(m18n.n('yunohost_configured'), 'success')
|
||||
|
||||
|
||||
def tools_update(ignore_apps=False, ignore_packages=False):
|
||||
|
@ -296,7 +301,7 @@ def tools_update(ignore_apps=False, ignore_packages=False):
|
|||
cache = apt.Cache()
|
||||
# Update APT cache
|
||||
if not cache.update():
|
||||
raise MoulinetteError(1, _("An error occured during APT cache update"))
|
||||
raise MoulinetteError(errno.EPERM, m18n.n('update_cache_failed'))
|
||||
|
||||
cache.open(None)
|
||||
cache.upgrade(True)
|
||||
|
@ -338,12 +343,11 @@ def tools_update(ignore_apps=False, ignore_packages=False):
|
|||
})
|
||||
|
||||
if len(apps) == 0 and len(packages) == 0:
|
||||
msignals.display(_("There is nothing to upgrade right now"), 'success')
|
||||
msignals.display(m18n.n('system_no_upgrade'), 'success')
|
||||
|
||||
return { 'packages': packages, 'apps': apps }
|
||||
|
||||
|
||||
|
||||
def tools_upgrade(ignore_apps=False, ignore_packages=False):
|
||||
"""
|
||||
Update apps & package cache, then display changelog
|
||||
|
@ -380,7 +384,7 @@ def tools_upgrade(ignore_apps=False, ignore_packages=False):
|
|||
app_upgrade()
|
||||
except: pass
|
||||
|
||||
msignals.display(_("System successfully upgraded"), 'success')
|
||||
msignals.display(m18n.n('system_upgraded'), 'success')
|
||||
|
||||
# Return API logs if it is an API call
|
||||
if not os.isatty(1):
|
||||
|
|
|
@ -29,6 +29,7 @@ import crypt
|
|||
import random
|
||||
import string
|
||||
import json
|
||||
import errno
|
||||
|
||||
from moulinette.core import MoulinetteError
|
||||
|
||||
|
@ -64,7 +65,8 @@ def user_list(auth, fields=None, filter=None, limit=None, offset=None):
|
|||
if attr in keys:
|
||||
attrs.append(attr)
|
||||
else:
|
||||
raise MoulinetteError(22, _("Invalid field '%s'") % attr)
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('field_invalid') % attr)
|
||||
else:
|
||||
attrs = [ 'uid', 'cn', 'mail' ]
|
||||
|
||||
|
@ -99,7 +101,7 @@ def user_create(auth, username, firstname, lastname, mail, password):
|
|||
|
||||
# Validate password length
|
||||
if len(password) < 4:
|
||||
raise MoulinetteError(22, _("Password is too short"))
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('password_too_short'))
|
||||
|
||||
auth.validate_uniqueness({
|
||||
'uid' : username,
|
||||
|
@ -107,10 +109,11 @@ def user_create(auth, username, firstname, lastname, mail, password):
|
|||
})
|
||||
|
||||
if mail[mail.find('@')+1:] not in domain_list(auth)['domains']:
|
||||
raise MoulinetteError(22, _("Unknown domain '%s'") % mail[mail.find('@')+1:])
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('mail_domain_unknown')
|
||||
% mail[mail.find('@')+1:])
|
||||
|
||||
# Get random UID/GID
|
||||
|
||||
uid_check = gid_check = 0
|
||||
while uid_check == 0 and gid_check == 0:
|
||||
uid = str(random.randint(200, 99999))
|
||||
|
@ -174,12 +177,12 @@ def user_create(auth, username, firstname, lastname, mail, password):
|
|||
os.system("su - %s -c ''" % username)
|
||||
os.system('yunohost app ssowatconf > /dev/null 2>&1')
|
||||
#TODO: Send a welcome mail to user
|
||||
msignals.display(_("User '%s' successfully created.") % username, 'success')
|
||||
msignals.display(m18n.n('user_created'), 'success')
|
||||
hook_callback('post_user_create', [username, mail, password, firstname, lastname])
|
||||
|
||||
return { 'fullname' : fullname, 'username' : username, 'mail' : mail }
|
||||
|
||||
raise MoulinetteError(169, _("An error occurred during user creation"))
|
||||
raise MoulinetteError(169, m18n.n('user_creation_failed'))
|
||||
|
||||
|
||||
def user_delete(auth, users, purge=False):
|
||||
|
@ -207,10 +210,10 @@ def user_delete(auth, users, purge=False):
|
|||
deleted.append(user)
|
||||
continue
|
||||
else:
|
||||
raise MoulinetteError(169, _("An error occurred during user deletion"))
|
||||
raise MoulinetteError(169, m18n.n('user_deletion_failed'))
|
||||
|
||||
os.system('yunohost app ssowatconf > /dev/null 2>&1')
|
||||
msignals.display(_("User(s) successfully deleted."), 'success')
|
||||
msignals.display(m18n.n('user_deleted'), 'success')
|
||||
return { 'users': deleted }
|
||||
|
||||
|
||||
|
@ -239,7 +242,7 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None, change
|
|||
# Populate user informations
|
||||
result = auth.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + username, attrs=attrs_to_fetch)
|
||||
if not result:
|
||||
raise MoulinetteError(167, _("Unknown username '%s'") % username)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown'))
|
||||
user = result[0]
|
||||
|
||||
# Get modifications from arguments
|
||||
|
@ -263,7 +266,9 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None, change
|
|||
if mail:
|
||||
auth.validate_uniqueness({ 'mail': mail })
|
||||
if mail[mail.find('@')+1:] not in domains:
|
||||
raise MoulinetteError(22, _("Unknown domain '%s'") % mail[mail.find('@')+1:])
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('mail_domain_unknown')
|
||||
% mail[mail.find('@')+1:])
|
||||
del user['mail'][0]
|
||||
new_attr_dict['mail'] = [mail] + user['mail']
|
||||
|
||||
|
@ -273,7 +278,9 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None, change
|
|||
for mail in add_mailalias:
|
||||
auth.validate_uniqueness({ 'mail': mail })
|
||||
if mail[mail.find('@')+1:] not in domains:
|
||||
raise MoulinetteError(22, _("Unknown domain '%s'") % mail[mail.find('@')+1:])
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('mail_domain_unknown')
|
||||
% mail[mail.find('@')+1:])
|
||||
user['mail'].append(mail)
|
||||
new_attr_dict['mail'] = user['mail']
|
||||
|
||||
|
@ -284,7 +291,8 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None, change
|
|||
if len(user['mail']) > 1 and mail in user['mail'][1:]:
|
||||
user['mail'].remove(mail)
|
||||
else:
|
||||
raise MoulinetteError(22, _("Invalid mail alias '%s'") % mail)
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('mail_alias_remove_failed') % mail)
|
||||
new_attr_dict['mail'] = user['mail']
|
||||
|
||||
if add_mailforward:
|
||||
|
@ -303,14 +311,15 @@ def user_update(auth, username, firstname=None, lastname=None, mail=None, change
|
|||
if len(user['maildrop']) > 1 and mail in user['maildrop'][1:]:
|
||||
user['maildrop'].remove(mail)
|
||||
else:
|
||||
raise MoulinetteError(22, _("Invalid mail forward '%s'") % mail)
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('mail_forward_remove_failed') % mail)
|
||||
new_attr_dict['maildrop'] = user['maildrop']
|
||||
|
||||
if auth.update('uid=%s,ou=users' % username, new_attr_dict):
|
||||
msignals.display(_("User '%s' successfully updated.") % username, 'success')
|
||||
msignals.display(m18n.n('user_updated'), 'success')
|
||||
return user_info(auth, username)
|
||||
else:
|
||||
raise MoulinetteError(169, _("An error occurred during user update"))
|
||||
raise MoulinetteError(169, m18n.n('user_update_failed'))
|
||||
|
||||
|
||||
def user_info(auth, username):
|
||||
|
@ -333,7 +342,7 @@ def user_info(auth, username):
|
|||
if result:
|
||||
user = result[0]
|
||||
else:
|
||||
raise MoulinetteError(22, _("Unknown username/mail '%s'") % username)
|
||||
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown'))
|
||||
|
||||
result_dict = {
|
||||
'username': user['uid'][0],
|
||||
|
@ -352,4 +361,4 @@ def user_info(auth, username):
|
|||
if result:
|
||||
return result_dict
|
||||
else:
|
||||
raise MoulinetteError(167, _("No user found"))
|
||||
raise MoulinetteError(167, m18n.n('user_info_failed'))
|
||||
|
|
26
locales/en.json
Normal file
26
locales/en.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"colon" : "%s: ",
|
||||
|
||||
"success" : "Success!",
|
||||
"warning" : "Warning:",
|
||||
"error" : "Error:",
|
||||
"permission_denied" : "Permission denied",
|
||||
"root_required" : "You must be root to perform this action",
|
||||
"instance_already_running" : "An instance is already running",
|
||||
|
||||
"unable_authenticate" : "Unable to authenticate",
|
||||
"unable_retrieve_session" : "Unable to retrieve the session",
|
||||
"error_ldap_operation" : "An error occured during LDAP operation",
|
||||
|
||||
"password" : "Password",
|
||||
"invalid_password" : "Invalid password",
|
||||
"confirm" : "Confirm",
|
||||
"values_mismatch" : "Values don't match",
|
||||
"authentication_required_long" : "Authentication is required to perform this action",
|
||||
"authentication_required" : "Authentication required",
|
||||
"authentication_profile_required" : "Authentication to profile '%s' required",
|
||||
"operation_interrupted" : "Operation interrupted",
|
||||
|
||||
"not_logged_in" : "You are not logged in",
|
||||
"server_already_running" : "A server is already running on that port"
|
||||
}
|
26
locales/fr.json
Normal file
26
locales/fr.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"colon" : "%s : ",
|
||||
|
||||
"success" : "Succès !",
|
||||
"warning" : "Attention :",
|
||||
"error" : "Erreur :",
|
||||
"permission_denied" : "Permission refusée",
|
||||
"root_required" : "Vous devez avoir les droits super-utilisateur pour exécuter cette action",
|
||||
"instance_already_running" : "Une instance est déjà en cours d'exécution",
|
||||
|
||||
"unable_authenticate" : "Impossible de vous authentifier",
|
||||
"unable_retrieve_session" : "Impossible de récupérer la session",
|
||||
"error_ldap_operation" : "Une erreur est survenue lors de l'opération LDAP",
|
||||
|
||||
"password" : "Mot de passe",
|
||||
"invalid_password" : "Mot de passe incorrect",
|
||||
"confirm" : "Confirmez",
|
||||
"values_mismatch" : "Les valeurs ne correspondent pas",
|
||||
"authentication_required_long" : "L'authentification est requise pour exécuter cette action",
|
||||
"authentication_required" : "Authentification requise",
|
||||
"authentication_profile_required" : "Authentification au profile '%s' requise",
|
||||
"operation_interrupted" : "Opération interrompue",
|
||||
|
||||
"not_logged_in" : "Vous n'êtes pas connecté",
|
||||
"server_already_running" : "Un server est déjà en cours d'exécution sur ce port"
|
||||
}
|
|
@ -50,13 +50,11 @@ def init(**kwargs):
|
|||
"""
|
||||
import sys
|
||||
import __builtin__
|
||||
from moulinette.core import Package, MoulinetteSignals, install_i18n
|
||||
from moulinette.core import Package, Moulinette18n, MoulinetteSignals
|
||||
__builtin__.__dict__['pkg'] = Package(**kwargs)
|
||||
__builtin__.__dict__['m18n'] = Moulinette18n(pkg)
|
||||
__builtin__.__dict__['msignals'] = MoulinetteSignals()
|
||||
|
||||
# Initialize internationalization
|
||||
install_i18n()
|
||||
|
||||
# Add library directory to python path
|
||||
sys.path.insert(0, pkg.libdir)
|
||||
|
||||
|
@ -104,6 +102,6 @@ def cli(namespaces, args, use_cache=True):
|
|||
'use_cache': use_cache})
|
||||
moulinette.run(args)
|
||||
except MoulinetteError as e:
|
||||
print(_('%s: %s' % (colorize(_('Error'), 'red'), e.strerror)))
|
||||
print('%s %s' % (colorize(m18n.g('error'), 'red'), e.strerror))
|
||||
return e.errno
|
||||
return 0
|
||||
|
|
|
@ -259,7 +259,7 @@ class ActionsMap(object):
|
|||
def __init__(self, parser, namespaces=[], use_cache=True):
|
||||
self.use_cache = use_cache
|
||||
if not issubclass(parser, BaseActionsMapParser):
|
||||
raise MoulinetteError(errno.EINVAL, _("Invalid parser class '%s'" % parser.__name__))
|
||||
raise ValueError("Invalid parser class '%s'" % parser.__name__)
|
||||
self._parser_class = parser
|
||||
|
||||
logging.debug("initializing ActionsMap for the interface '%s'" % parser.interface)
|
||||
|
@ -311,7 +311,7 @@ class ActionsMap(object):
|
|||
try:
|
||||
auth = self.parser.get_global_conf('authenticator', profile)[1]
|
||||
except KeyError:
|
||||
raise MoulinetteError(errno.EINVAL, _("Unknown authenticator profile '%s'") % profile)
|
||||
raise ValueError("Unknown authenticator profile '%s'" % profile)
|
||||
else:
|
||||
return auth()
|
||||
|
||||
|
@ -343,9 +343,11 @@ class ActionsMap(object):
|
|||
fromlist=[func_name])
|
||||
func = getattr(mod, func_name)
|
||||
except (AttributeError, ImportError):
|
||||
raise MoulinetteError(errno.ENOSYS, _('Function is not defined'))
|
||||
raise ImportError("Unable to load function %s.%s/%s"
|
||||
% (namespace, category, func_name))
|
||||
else:
|
||||
# Process the action
|
||||
# Load translation and process the action
|
||||
m18n.load_namespace(namespace)
|
||||
return func(**arguments)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -93,7 +93,7 @@ class BaseAuthenticator(object):
|
|||
s_id, s_hash = token
|
||||
except TypeError:
|
||||
if not password:
|
||||
raise MoulinetteError(errno.EINVAL, _("Invalid format for token"))
|
||||
raise ValueError("Invalid token format")
|
||||
else:
|
||||
# TODO: Log error
|
||||
store_session = False
|
||||
|
@ -108,9 +108,9 @@ class BaseAuthenticator(object):
|
|||
except MoulinetteError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logging.error("authentication (name: '%s', type: '%s') fails: %s" % \
|
||||
(self.name, self.vendor, e))
|
||||
raise MoulinetteError(errno.EACCES, _("Unable to authenticate"))
|
||||
logging.error("authentication (name: '%s', type: '%s') fails: %s" \
|
||||
% (self.name, self.vendor, e))
|
||||
raise MoulinetteError(errno.EACCES, m18n.g('unable_authenticate'))
|
||||
|
||||
# Store session
|
||||
if store_session:
|
||||
|
@ -140,8 +140,8 @@ class BaseAuthenticator(object):
|
|||
with self._open_sessionfile(session_id, 'r') as f:
|
||||
enc_pwd = f.read()
|
||||
except IOError:
|
||||
# TODO: Set proper error code
|
||||
raise MoulinetteError(167, _("Unable to retrieve session"))
|
||||
raise MoulinetteError(errno.ENOENT,
|
||||
m18r.g('unable_retrieve_session'))
|
||||
else:
|
||||
gpg = gnupg.GPG()
|
||||
gpg.encoding = 'utf-8'
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
# TODO: Use Python3 to remove this fix!
|
||||
from __future__ import absolute_import
|
||||
import errno
|
||||
import ldap
|
||||
import ldap.modlist as modlist
|
||||
|
||||
|
@ -64,7 +65,7 @@ class Authenticator(BaseAuthenticator):
|
|||
else:
|
||||
con.simple_bind_s()
|
||||
except ldap.INVALID_CREDENTIALS:
|
||||
raise MoulinetteError(errno.EACCES, _("Invalid password"))
|
||||
raise MoulinetteError(errno.EACCES, m18n.g('invalid_password'))
|
||||
else:
|
||||
self.con = con
|
||||
|
||||
|
@ -93,7 +94,7 @@ class Authenticator(BaseAuthenticator):
|
|||
try:
|
||||
result = self.con.search_s(base, ldap.SCOPE_SUBTREE, filter, attrs)
|
||||
except:
|
||||
raise MoulinetteError(169, _('An error occured during LDAP search'))
|
||||
raise MoulinetteError(169, m18n.g('error_ldap_operation'))
|
||||
|
||||
result_list = []
|
||||
if not attrs or 'dn' not in attrs:
|
||||
|
@ -122,7 +123,7 @@ class Authenticator(BaseAuthenticator):
|
|||
try:
|
||||
self.con.add_s(dn, ldif)
|
||||
except:
|
||||
raise MoulinetteError(169, _('An error occured during LDAP entry creation'))
|
||||
raise MoulinetteError(169, m18n.g('error_ldap_operation'))
|
||||
else:
|
||||
return True
|
||||
|
||||
|
@ -141,7 +142,7 @@ class Authenticator(BaseAuthenticator):
|
|||
try:
|
||||
self.con.delete_s(dn)
|
||||
except:
|
||||
raise MoulinetteError(169, _('An error occured during LDAP entry deletion'))
|
||||
raise MoulinetteError(169, m18n.g('error_ldap_operation'))
|
||||
else:
|
||||
return True
|
||||
|
||||
|
@ -169,7 +170,7 @@ class Authenticator(BaseAuthenticator):
|
|||
|
||||
self.con.modify_ext_s(dn, ldif)
|
||||
except:
|
||||
raise MoulinetteError(169, _('An error occured during LDAP entry update'))
|
||||
raise MoulinetteError(169, m18n.g('error_ldap_operation'))
|
||||
else:
|
||||
return True
|
||||
|
||||
|
@ -188,5 +189,5 @@ class Authenticator(BaseAuthenticator):
|
|||
if not self.search(filter=attr + '=' + value):
|
||||
continue
|
||||
else:
|
||||
raise MoulinetteError(17, _('Attribute already exists') + ' "' + attr + '=' + value + '"')
|
||||
raise MoulinetteError(17, 'Attribute already exists "%s=%s"' % (attr, value))
|
||||
return True
|
||||
|
|
|
@ -3,35 +3,14 @@
|
|||
import os
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import errno
|
||||
import gettext
|
||||
import logging
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
# Package manipulation -------------------------------------------------
|
||||
|
||||
def install_i18n(namespace=None):
|
||||
"""Install internationalization
|
||||
|
||||
Install translation based on the package's default gettext domain or
|
||||
on 'namespace' if provided.
|
||||
|
||||
Keyword arguments:
|
||||
- namespace -- The namespace to initialize i18n for
|
||||
|
||||
"""
|
||||
if namespace:
|
||||
try:
|
||||
t = gettext.translation(namespace, pkg.localedir)
|
||||
except IOError:
|
||||
# TODO: Log error
|
||||
return
|
||||
else:
|
||||
t.install()
|
||||
else:
|
||||
gettext.install('moulinette', pkg.localedir)
|
||||
|
||||
class Package(object):
|
||||
"""Package representation and easy access methods
|
||||
|
||||
|
@ -51,7 +30,7 @@ class Package(object):
|
|||
# Set local directories
|
||||
self._datadir = '%s/data' % basedir
|
||||
self._libdir = '%s/lib' % basedir
|
||||
self._localedir = '%s/po' % basedir
|
||||
self._localedir = '%s/locales' % basedir
|
||||
self._cachedir = '%s/cache' % basedir
|
||||
else:
|
||||
import package
|
||||
|
@ -130,6 +109,189 @@ class Package(object):
|
|||
True if mode[0] == 'w' else False)
|
||||
return open('%s/%s' % (self.get_cachedir(**kwargs), filename), mode)
|
||||
|
||||
|
||||
# Internationalization -------------------------------------------------
|
||||
|
||||
class Translator(object):
|
||||
"""Internationalization class
|
||||
|
||||
Provide an internationalization mechanism based on JSON files to
|
||||
translate a key in the proper locale.
|
||||
|
||||
Keyword arguments:
|
||||
- locale_dir -- The directory where locale files are located
|
||||
- default_locale -- The default locale to use
|
||||
|
||||
"""
|
||||
def __init__(self, locale_dir, default_locale='en'):
|
||||
self.locale_dir = locale_dir
|
||||
self.locale = default_locale
|
||||
self._translations = {}
|
||||
|
||||
# Attempt to load default translations
|
||||
if not self._load_translations(default_locale):
|
||||
raise ValueError("Unable to load locale '%s' from '%s'"
|
||||
% (default_locale, locale_dir))
|
||||
self.default_locale = default_locale
|
||||
|
||||
def get_locales(self):
|
||||
"""Return a list of the avalaible locales"""
|
||||
locales = []
|
||||
|
||||
for f in os.listdir(self.locale_dir):
|
||||
if f.endswith('.json'):
|
||||
# TODO: Validate locale
|
||||
locales.append(f[:-5])
|
||||
return locales
|
||||
|
||||
def set_locale(self, locale):
|
||||
"""Set the locale to use
|
||||
|
||||
Set the locale to use at first. If the locale is not available,
|
||||
the default locale is used.
|
||||
|
||||
Keyword arguments:
|
||||
- locale -- The locale to use
|
||||
|
||||
Returns:
|
||||
True if the locale has been set, otherwise False
|
||||
|
||||
"""
|
||||
if locale not in self._translations:
|
||||
if not self._load_translations(locale):
|
||||
logging.info("unable to load locale '%s' from '%s'"
|
||||
% (self.default_locale, self.locale_dir))
|
||||
|
||||
# Revert to default locale
|
||||
self.locale = self.default_locale
|
||||
return False
|
||||
|
||||
# Set current locale
|
||||
self.locale = locale
|
||||
return True
|
||||
|
||||
def translate(self, key):
|
||||
"""Retrieve proper translation for a key
|
||||
|
||||
Attempt to retrieve translation for a key using the current locale
|
||||
or the default locale if 'key' is not found.
|
||||
|
||||
Keyword arguments:
|
||||
- key -- The key to translate
|
||||
|
||||
"""
|
||||
try:
|
||||
value = self._translations[self.locale][key]
|
||||
except KeyError:
|
||||
try:
|
||||
value = self._translations[self.default_locale][key]
|
||||
logging.info("untranslated key '%s' for locale '%s'" %
|
||||
(key, self.locale))
|
||||
except KeyError:
|
||||
logging.warning("unknown key '%s' for locale '%s'" %
|
||||
(key, self.default_locale))
|
||||
return key
|
||||
return value
|
||||
|
||||
def _load_translations(self, locale, overwrite=False):
|
||||
"""Load translations for a locale
|
||||
|
||||
Attempt to load translations for a given locale. If 'overwrite' is
|
||||
True, translations will be loaded again.
|
||||
|
||||
Keyword arguments:
|
||||
- locale -- The locale to load
|
||||
- overwrite -- True to overwrite existing translations
|
||||
|
||||
Returns:
|
||||
True if the translations have been loaded, otherwise False
|
||||
|
||||
"""
|
||||
if not overwrite and locale in self._translations:
|
||||
return True
|
||||
|
||||
try:
|
||||
with open('%s/%s.json' % (self.locale_dir, locale), 'r') as f:
|
||||
j = json.load(f)
|
||||
except IOError:
|
||||
return False
|
||||
else:
|
||||
self._translations[locale] = j
|
||||
return True
|
||||
|
||||
|
||||
class Moulinette18n(object):
|
||||
"""Internationalization service for the moulinette
|
||||
|
||||
Manage internationalization and access to the proper keys translation
|
||||
used in the moulinette and libraries.
|
||||
|
||||
Keyword arguments:
|
||||
- package -- The current Package instance
|
||||
- default_locale -- The default locale to use
|
||||
|
||||
"""
|
||||
def __init__(self, package, default_locale='en'):
|
||||
self.default_locale = default_locale
|
||||
self.locale = default_locale
|
||||
self.pkg = package
|
||||
|
||||
# Init translators
|
||||
self._global = Translator(self.pkg.localedir, default_locale)
|
||||
self._namespace = None
|
||||
|
||||
def load_namespace(self, namespace):
|
||||
"""Load the namespace to use
|
||||
|
||||
Load and set translations of a given namespace. Those translations
|
||||
are accessible with Moulinette18n.n().
|
||||
|
||||
Keyword arguments:
|
||||
- namespace -- The namespace to load
|
||||
|
||||
"""
|
||||
if self._namespace and self._namespace[0] == namespace:
|
||||
return
|
||||
|
||||
self._namespace = (namespace, Translator('%s/%s/locales'
|
||||
% (self.pkg.libdir, namespace), self.default_locale))
|
||||
self._namespace[1].set_locale(self.locale)
|
||||
|
||||
def set_locale(self, locale):
|
||||
"""Set the locale to use"""
|
||||
self.locale = locale
|
||||
|
||||
self._global.set_locale(locale)
|
||||
if self._namespace:
|
||||
self._namespace[1].set_locale(locale)
|
||||
|
||||
def g(self, key):
|
||||
"""Retrieve proper translation for a moulinette key
|
||||
|
||||
Attempt to retrieve value for a key from moulinette translations
|
||||
using the current locale or the default locale if 'key' is not found.
|
||||
|
||||
Keyword arguments:
|
||||
- key -- The key to translate
|
||||
|
||||
"""
|
||||
return self._global.translate(key)
|
||||
|
||||
def n(self, key):
|
||||
"""Retrieve proper translation for a moulinette key
|
||||
|
||||
Attempt to retrieve value for a key from loaded namespace translations
|
||||
using the current locale or the default locale if 'key' is not found.
|
||||
|
||||
Keyword arguments:
|
||||
- key -- The key to translate
|
||||
|
||||
"""
|
||||
if not self._namespace:
|
||||
raise RuntimeError("No namespace loaded for translation")
|
||||
return self._namespace[1].translate(key)
|
||||
|
||||
|
||||
class MoulinetteSignals(object):
|
||||
"""Signals connector for the moulinette
|
||||
|
||||
|
@ -256,16 +418,16 @@ def init_interface(name, kwargs={}, actionsmap={}):
|
|||
|
||||
try:
|
||||
mod = import_module('moulinette.interfaces.%s' % name)
|
||||
except ImportError:
|
||||
except ImportError as e:
|
||||
# TODO: List available interfaces
|
||||
raise MoulinetteError(errno.EINVAL, _("Unknown interface '%s'" % name))
|
||||
raise ImportError("Unable to load interface '%s': %s" % (name, str(e)))
|
||||
else:
|
||||
try:
|
||||
# Retrieve interface classes
|
||||
parser = mod.ActionsMapParser
|
||||
interface = mod.Interface
|
||||
except AttributeError as e:
|
||||
raise MoulinetteError(errno.EFAULT, _("Invalid interface '%s': %s") % (name, e))
|
||||
raise ImportError("Invalid interface '%s': %s" % (name, e))
|
||||
|
||||
# Instantiate or retrieve ActionsMap
|
||||
if isinstance(actionsmap, dict):
|
||||
|
@ -273,7 +435,7 @@ def init_interface(name, kwargs={}, actionsmap={}):
|
|||
elif isinstance(actionsmap, ActionsMap):
|
||||
amap = actionsmap
|
||||
else:
|
||||
raise MoulinetteError(errno.EINVAL, _("Invalid actions map '%r'" % actionsmap))
|
||||
raise ValueError("Invalid actions map '%r'" % actionsmap)
|
||||
|
||||
return interface(amap, **kwargs)
|
||||
|
||||
|
@ -293,7 +455,8 @@ def init_authenticator((vendor, name), kwargs={}):
|
|||
mod = import_module('moulinette.authenticators.%s' % vendor)
|
||||
except ImportError as e:
|
||||
# TODO: List available authenticators vendors
|
||||
raise MoulinetteError(errno.EINVAL, _("Unable to load authenticator vendor '%s': %s") % (vendor, str(e)))
|
||||
raise ImportError("Unable to load authenticator vendor '%s': %s"
|
||||
% (vendor, str(e)))
|
||||
else:
|
||||
return mod.Authenticator(name, **kwargs)
|
||||
|
||||
|
@ -369,12 +532,13 @@ class MoulinetteLock(object):
|
|||
try:
|
||||
(open(self._lockfile, 'w')).close()
|
||||
except IOError:
|
||||
raise MoulinetteError(errno.EPERM, _("Permission denied, did you forget 'sudo' ?"))
|
||||
raise MoulinetteError(errno.EPERM,
|
||||
'%s. %s.' % (m18n.g('permission_denied'), m18n.g('root_required')))
|
||||
break
|
||||
|
||||
if (time.time() - start_time) > self.timeout:
|
||||
raise MoulinetteError(errno.EBUSY, _("An instance is already running for '%s'") \
|
||||
% self.namespace)
|
||||
raise MoulinetteError(errno.EBUSY,
|
||||
m18n.g('instance_already_running'))
|
||||
# Wait before checking again
|
||||
time.sleep(self.interval)
|
||||
self._locked = True
|
||||
|
|
|
@ -122,7 +122,7 @@ class _ActionsMapPlugin(object):
|
|||
try:
|
||||
kwargs['password'] = request.POST['password']
|
||||
except KeyError:
|
||||
raise HTTPBadRequestResponse(_("Missing password parameter"))
|
||||
raise HTTPBadRequestResponse("Missing password parameter")
|
||||
try:
|
||||
kwargs['profile'] = request.POST['profile']
|
||||
except KeyError:
|
||||
|
@ -235,7 +235,7 @@ class _ActionsMapPlugin(object):
|
|||
try:
|
||||
del self.secrets[s_id]
|
||||
except KeyError:
|
||||
raise HTTPUnauthorizedResponse(_("You are not logged in"))
|
||||
raise HTTPUnauthorizedResponse(m18n.g('not_logged_in'))
|
||||
else:
|
||||
# TODO: Clean the session for profile only
|
||||
# Delete cookie and clean the session
|
||||
|
@ -278,9 +278,9 @@ class _ActionsMapPlugin(object):
|
|||
secret=s_secret)[authenticator.name]
|
||||
except KeyError:
|
||||
if authenticator.name == 'default':
|
||||
msg = _("Needing authentication")
|
||||
msg = m18n.g('authentication_required')
|
||||
else:
|
||||
msg = _("Needing authentication to profile '%s'") % authenticator.name
|
||||
msg = m18n.g('authentication_profile_required') % authenticator.name
|
||||
raise HTTPUnauthorizedResponse(msg)
|
||||
else:
|
||||
return authenticator(token=(s_id, s_hash))
|
||||
|
@ -405,7 +405,7 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
auth = msignals.authenticate(klass(), **auth_conf)
|
||||
if not auth.is_authenticated:
|
||||
# TODO: Set proper error code
|
||||
raise MoulinetteError(errno.EACCES, _("This action need authentication"))
|
||||
raise MoulinetteError(errno.EACCES, m18n.g('authentication_required_long'))
|
||||
if self.get_conf(tid, 'argument_auth') and \
|
||||
self.get_conf(tid, 'authenticate') == 'all':
|
||||
ret.auth = auth
|
||||
|
@ -466,7 +466,8 @@ class Interface(BaseInterface):
|
|||
run(self._app, port=_port)
|
||||
except IOError as e:
|
||||
if e.args[0] == errno.EADDRINUSE:
|
||||
raise MoulinetteError(errno.EADDRINUSE, _("A server is already running"))
|
||||
raise MoulinetteError(errno.EADDRINUSE,
|
||||
m18n.g('server_already_running'))
|
||||
raise
|
||||
|
||||
|
||||
|
|
|
@ -137,8 +137,8 @@ class ActionsMapParser(BaseActionsMapParser):
|
|||
# TODO: Catch errors
|
||||
auth = msignals.authenticate(klass(), **auth_conf)
|
||||
if not auth.is_authenticated:
|
||||
# TODO: Set proper error code
|
||||
raise MoulinetteError(errno.EACCES, _("This action need authentication"))
|
||||
raise MoulinetteError(errno.EACCES,
|
||||
m18n.g('authentication_required_long'))
|
||||
if self.get_conf(ret._tid, 'argument_auth') and \
|
||||
self.get_conf(ret._tid, 'authenticate') == 'all':
|
||||
ret.auth = auth
|
||||
|
@ -157,6 +157,12 @@ class Interface(BaseInterface):
|
|||
|
||||
"""
|
||||
def __init__(self, actionsmap):
|
||||
import locale
|
||||
|
||||
# Set user locale
|
||||
lang = locale.getdefaultlocale()[0]
|
||||
m18n.set_locale(lang[:2])
|
||||
|
||||
# Connect signals to handlers
|
||||
msignals.set_handler('authenticate', self._do_authenticate)
|
||||
msignals.set_handler('display', self._do_display)
|
||||
|
@ -177,7 +183,7 @@ class Interface(BaseInterface):
|
|||
try:
|
||||
ret = self.actionsmap.process(args, timeout=5)
|
||||
except KeyboardInterrupt, EOFError:
|
||||
raise MoulinetteError(errno.EINTR, _("Interrupted"))
|
||||
raise MoulinetteError(errno.EINTR, m18n.g('operation_interrupted'))
|
||||
|
||||
if isinstance(ret, dict):
|
||||
pretty_print_dict(ret)
|
||||
|
@ -194,7 +200,7 @@ class Interface(BaseInterface):
|
|||
|
||||
"""
|
||||
# TODO: Allow token authentication?
|
||||
msg = help or _("Password")
|
||||
msg = help or m18n.g('password')
|
||||
return authenticator(password=self._do_prompt(msg, True, False))
|
||||
|
||||
def _do_prompt(self, message, is_password, confirm):
|
||||
|
@ -204,14 +210,15 @@ class Interface(BaseInterface):
|
|||
|
||||
"""
|
||||
if is_password:
|
||||
prompt = lambda m: getpass.getpass(colorize(_('%s: ') % m, 'blue'))
|
||||
prompt = lambda m: getpass.getpass(colorize(m18n.g('colon') % m,
|
||||
'blue'))
|
||||
else:
|
||||
prompt = lambda m: raw_input(colorize(_('%s: ') % m, 'blue'))
|
||||
prompt = lambda m: raw_input(colorize(m18n.g('colon') % m, 'blue'))
|
||||
value = prompt(message)
|
||||
|
||||
if confirm:
|
||||
if prompt(_('Retype %s') % message) != value:
|
||||
raise MoulinetteError(errno.EINVAL, _("Values don't match"))
|
||||
if prompt('%s %s' % (m18n.g('confirm'), message)) != value:
|
||||
raise MoulinetteError(errno.EINVAL, m18n.g('values_mismatch'))
|
||||
|
||||
return value
|
||||
|
||||
|
@ -222,8 +229,8 @@ class Interface(BaseInterface):
|
|||
|
||||
"""
|
||||
if style == 'success':
|
||||
print('%s %s' % (colorize(_("Success!"), 'green'), message))
|
||||
print('%s %s' % (colorize(m18n.g('success'), 'green'), message))
|
||||
elif style == 'warning':
|
||||
print('%s %s' % (colorize(_("Warning!"), 'yellow'), message))
|
||||
print('%s %s' % (colorize(m18n.g('warning'), 'yellow'), message))
|
||||
else:
|
||||
print(message)
|
||||
|
|
Loading…
Reference in a new issue