mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-09-19 04:59:01 +00:00
email: implemented service alert
- Better error handling - You may retroactively diagnose and fix problems - Shows the most important issues first audit.models.Diagnosis - Added JSON serialization (needed for IPC) - Replaced ambiguous vocabulary - Provided a sorting key audit, diagnosis - Support title translation
This commit is contained in:
parent
74bf8dc4a8
commit
f400eb9439
@ -6,8 +6,9 @@ Provides diagnosis and repair of email server configuration issues
|
|||||||
from . import domain
|
from . import domain
|
||||||
from . import home
|
from . import home
|
||||||
from . import ldap
|
from . import ldap
|
||||||
|
from . import models
|
||||||
from . import rcube
|
from . import rcube
|
||||||
from . import spam
|
from . import spam
|
||||||
from . import tls
|
from . import tls
|
||||||
|
|
||||||
__all__ = ['domain', 'home', 'ldap', 'rcube', 'spam', 'tls']
|
__all__ = ['domain', 'home', 'ldap', 'models', 'rcube', 'spam', 'tls']
|
||||||
|
|||||||
@ -4,6 +4,7 @@ configurations"""
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from plinth import actions
|
from plinth import actions
|
||||||
|
|
||||||
import plinth.modules.email_server.postconf as postconf
|
import plinth.modules.email_server.postconf as postconf
|
||||||
@ -61,11 +62,15 @@ def get():
|
|||||||
Recommended endpoint name:
|
Recommended endpoint name:
|
||||||
GET /audit/ldap
|
GET /audit/ldap
|
||||||
"""
|
"""
|
||||||
|
translation_table = [
|
||||||
|
(check_sasl, _('Postfix-Dovecot SASL integration')),
|
||||||
|
(check_alias_maps, _('Postfix alias maps')),
|
||||||
|
(check_local_recipient_maps, _('Postfix local recipient maps')),
|
||||||
|
]
|
||||||
results = []
|
results = []
|
||||||
with postconf.mutex.lock_all():
|
with postconf.mutex.lock_all():
|
||||||
results.append(check_sasl())
|
for check, title in translation_table:
|
||||||
results.append(check_alias_maps())
|
results.append(check(title))
|
||||||
results.append(check_local_recipient_maps())
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@ -85,8 +90,8 @@ def action_set_up():
|
|||||||
action_set_ulookup()
|
action_set_ulookup()
|
||||||
|
|
||||||
|
|
||||||
def check_sasl():
|
def check_sasl(title=''):
|
||||||
diagnosis = models.MainCfDiagnosis('Postfix-Dovecot SASL integration')
|
diagnosis = models.MainCfDiagnosis(title)
|
||||||
diagnosis.compare(default_config, postconf.get_many_unsafe)
|
diagnosis.compare(default_config, postconf.get_many_unsafe)
|
||||||
return diagnosis
|
return diagnosis
|
||||||
|
|
||||||
@ -109,9 +114,9 @@ def action_set_submission():
|
|||||||
options=default_smtps_options)
|
options=default_smtps_options)
|
||||||
|
|
||||||
|
|
||||||
def check_alias_maps():
|
def check_alias_maps(title=''):
|
||||||
"""Check the ability to mail to usernames and user aliases"""
|
"""Check the ability to mail to usernames and user aliases"""
|
||||||
diagnosis = models.MainCfDiagnosis('Postfix alias maps')
|
diagnosis = models.MainCfDiagnosis(title)
|
||||||
|
|
||||||
analysis = models.AliasMapsAnalysis()
|
analysis = models.AliasMapsAnalysis()
|
||||||
analysis.parsed = postconf.parse_maps_by_key_unsafe('alias_maps')
|
analysis.parsed = postconf.parse_maps_by_key_unsafe('alias_maps')
|
||||||
@ -152,8 +157,8 @@ def rearrange_alias_maps(analysis):
|
|||||||
return ' '.join(filter(None, analysis.parsed))
|
return ' '.join(filter(None, analysis.parsed))
|
||||||
|
|
||||||
|
|
||||||
def check_local_recipient_maps():
|
def check_local_recipient_maps(title=''):
|
||||||
diagnosis = models.MainCfDiagnosis('Postfix local recipient maps')
|
diagnosis = models.MainCfDiagnosis(title)
|
||||||
lrcpt_maps = postconf.parse_maps_by_key_unsafe('local_recipient_maps')
|
lrcpt_maps = postconf.parse_maps_by_key_unsafe('local_recipient_maps')
|
||||||
list_modified = False
|
list_modified = False
|
||||||
|
|
||||||
|
|||||||
@ -15,18 +15,47 @@ class UnresolvedIssueError(AssertionError):
|
|||||||
class Diagnosis:
|
class Diagnosis:
|
||||||
"""Records a diagnosis: what went wrong and how to fix them"""
|
"""Records a diagnosis: what went wrong and how to fix them"""
|
||||||
|
|
||||||
def __init__(self, title):
|
def __init__(self, title='', action=''):
|
||||||
"""Class constructor"""
|
"""Class constructor"""
|
||||||
self.title = title
|
self.title = title
|
||||||
self.fails = []
|
self.action = action
|
||||||
|
self.critical = []
|
||||||
self.errors = []
|
self.errors = []
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
"""Serialize object to JSON"""
|
||||||
|
return {
|
||||||
|
'class': self.__class__.__name__,
|
||||||
|
'title': self.title,
|
||||||
|
'action': self.action,
|
||||||
|
'errors': self.errors,
|
||||||
|
'critical': self.critical
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, valid_dict, translate=None):
|
||||||
|
"""Construct a Diagnosis instance from a valid JSON dictionary.
|
||||||
|
|
||||||
|
:type valid_dict: dict
|
||||||
|
:param valid_dict: a valid dictionary representation
|
||||||
|
:type translate: str -> Union[str, None]
|
||||||
|
:param translate: optional; if specified, should be a function that
|
||||||
|
accepts the title and returns a new title or None.
|
||||||
|
"""
|
||||||
|
title = valid_dict['title']
|
||||||
|
if translate:
|
||||||
|
title = translate(title) or title
|
||||||
|
result = cls(title, action=valid_dict['action'])
|
||||||
|
result.errors.extend(valid_dict['errors'])
|
||||||
|
result.critical.extend(valid_dict['critical'])
|
||||||
|
return result
|
||||||
|
|
||||||
def critical(self, message_fmt, *args):
|
def critical(self, message_fmt, *args):
|
||||||
"""Append a message to the fails list"""
|
"""Append a message to the critical errors list"""
|
||||||
if args:
|
if args:
|
||||||
self.fails.append(message_fmt % args)
|
self.critical.append(message_fmt % args)
|
||||||
else:
|
else:
|
||||||
self.fails.append(message_fmt)
|
self.critical.append(message_fmt)
|
||||||
|
|
||||||
def error(self, message_fmt, *args):
|
def error(self, message_fmt, *args):
|
||||||
"""Append a message to the errors list"""
|
"""Append a message to the errors list"""
|
||||||
@ -40,28 +69,37 @@ class Diagnosis:
|
|||||||
if log:
|
if log:
|
||||||
self.write_logs()
|
self.write_logs()
|
||||||
|
|
||||||
if self.errors:
|
if self.critical:
|
||||||
return [self.title, 'error']
|
return [self.title, 'error']
|
||||||
elif self.fails:
|
elif self.errors:
|
||||||
return [self.title, 'failed']
|
return [self.title, 'failed']
|
||||||
else:
|
else:
|
||||||
return [self.title, 'passed']
|
return [self.title, 'passed']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_failed(self):
|
||||||
|
"""True if the diagnosis has failed or contains an error"""
|
||||||
|
return (self.critical or self.errors)
|
||||||
|
|
||||||
def write_logs(self):
|
def write_logs(self):
|
||||||
"""Log errors and failures"""
|
"""Log errors and failures"""
|
||||||
logger.debug('Ran audit: %s', self.title)
|
logger.debug('Ran audit: %s', self.title)
|
||||||
for message in self.errors:
|
for message in self.critical:
|
||||||
logger.critical(message)
|
logger.critical(message)
|
||||||
for message in self.fails:
|
for message in self.errors:
|
||||||
logger.error(message)
|
logger.error(message)
|
||||||
|
|
||||||
|
def sorting_key(self):
|
||||||
|
"""The key function for list.sort"""
|
||||||
|
return (-len(self.critical), -len(self.errors), self.title)
|
||||||
|
|
||||||
|
|
||||||
class MainCfDiagnosis(Diagnosis):
|
class MainCfDiagnosis(Diagnosis):
|
||||||
"""Diagnosis for a set of main.cf configuration keys"""
|
"""Diagnosis for a set of main.cf configuration keys"""
|
||||||
|
|
||||||
def __init__(self, title):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Class constructor"""
|
"""Class constructor. See :class:`.Diagnosis` for method signature"""
|
||||||
super().__init__(title)
|
super().__init__(*args, **kwargs)
|
||||||
self.advice = {}
|
self.advice = {}
|
||||||
self.user = {}
|
self.user = {}
|
||||||
|
|
||||||
|
|||||||
@ -27,18 +27,15 @@ rcube_mutex = Mutex('rcube-config')
|
|||||||
|
|
||||||
|
|
||||||
def get():
|
def get():
|
||||||
translation_table = {
|
translation = {
|
||||||
'rc_installed': _('RoundCube availability'),
|
'rc_installed': _('RoundCube availability'),
|
||||||
'rc_config_header': _('FreedomBox header in RoundCube config'),
|
'rc_config_header': _('RoundCube configured for FreedomBox email'),
|
||||||
}
|
}
|
||||||
|
|
||||||
output = actions.superuser_run('email_server', ['-i', 'rcube', 'check'])
|
output = actions.superuser_run('email_server', ['-i', 'rcube', 'check'])
|
||||||
results = json.loads(output)
|
results = json.loads(output)
|
||||||
for i in range(0, len(results)):
|
for i in range(0, len(results)):
|
||||||
name = translation_table.get(results[i][0], results[i][0])
|
results[i] = models.Diagnosis.from_json(results[i], translation.get)
|
||||||
diagnosis = models.Diagnosis(name)
|
|
||||||
if results[i][1] == 'error':
|
|
||||||
diagnosis.error('Failed')
|
|
||||||
results[i] = diagnosis
|
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@ -47,23 +44,35 @@ def repair():
|
|||||||
actions.superuser_run('email_server', ['-i', 'rcube', 'set_up'])
|
actions.superuser_run('email_server', ['-i', 'rcube', 'set_up'])
|
||||||
|
|
||||||
|
|
||||||
|
def repair_component(action):
|
||||||
|
action_to_services = {'set_up': []}
|
||||||
|
if action not in action_to_services:
|
||||||
|
return
|
||||||
|
actions.superuser_run('email_server', ['-i', 'rcube', action])
|
||||||
|
return action_to_services[action]
|
||||||
|
|
||||||
|
|
||||||
def action_check():
|
def action_check():
|
||||||
results = _action_check()
|
results = _action_check()
|
||||||
|
for i in range(0, len(results)):
|
||||||
|
results[i] = results[i].to_json()
|
||||||
print(json.dumps(results))
|
print(json.dumps(results))
|
||||||
|
|
||||||
|
|
||||||
def _action_check():
|
def _action_check():
|
||||||
results = []
|
results = []
|
||||||
if not os.path.exists(config_path):
|
if not os.path.exists(config_path):
|
||||||
results.append(['rc_installed', 'error'])
|
diagnosis = models.Diagnosis('rc_installed')
|
||||||
|
diagnosis.error('Config file was missing')
|
||||||
|
diagnosis.error('Check that RoundCube has been installed')
|
||||||
|
results.append(diagnosis)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
diagnosis = models.Diagnosis('rc_config_header', action='set_up')
|
||||||
injector = ConfigInjector(boundary_pattern, boundary_format)
|
injector = ConfigInjector(boundary_pattern, boundary_format)
|
||||||
if injector.has_header_line(config_path):
|
if not injector.has_header_line(config_path):
|
||||||
results.append(['rc_config_header', 'pass'])
|
diagnosis.error('FreedomBox header line was missing')
|
||||||
else:
|
results.append(diagnosis)
|
||||||
results.append(['rc_config_header', 'error'])
|
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from plinth import actions
|
from plinth import actions
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
@ -81,9 +82,13 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def get():
|
def get():
|
||||||
|
translation_table = [
|
||||||
|
(check_filter, _('Inbound and outbound mail filters')),
|
||||||
|
]
|
||||||
results = []
|
results = []
|
||||||
with postconf.mutex.lock_all():
|
with postconf.mutex.lock_all():
|
||||||
results.append(check_filter())
|
for check, title in translation_table:
|
||||||
|
results.append(check(title))
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
@ -91,8 +96,8 @@ def repair():
|
|||||||
actions.superuser_run('email_server', ['-i', 'spam', 'set_filter'])
|
actions.superuser_run('email_server', ['-i', 'spam', 'set_filter'])
|
||||||
|
|
||||||
|
|
||||||
def check_filter():
|
def check_filter(title=''):
|
||||||
diagnosis = models.MainCfDiagnosis('Inbound and outbound mail filters')
|
diagnosis = models.MainCfDiagnosis(title)
|
||||||
diagnosis.compare(milter_config, postconf.get_many_unsafe)
|
diagnosis.compare(milter_config, postconf.get_many_unsafe)
|
||||||
return diagnosis
|
return diagnosis
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
"""TLS configuration"""
|
"""TLS configuration"""
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from plinth import actions
|
from plinth import actions
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
@ -67,17 +70,44 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def get():
|
def get():
|
||||||
results = []
|
results = []
|
||||||
with postconf.mutex.lock_all():
|
_get_regular_results(results)
|
||||||
results.append(check_tls())
|
_get_superuser_results(results)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def _get_regular_results(results):
|
||||||
|
translation_table = [
|
||||||
|
(check_tls, _('Postfix TLS parameters')),
|
||||||
|
(check_postfix_cert_usage, _('Postfix uses a TLS certificate')),
|
||||||
|
]
|
||||||
|
with postconf.mutex.lock_all():
|
||||||
|
for check, title in translation_table:
|
||||||
|
results.append(check(title))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_superuser_results(results):
|
||||||
|
translation = {
|
||||||
|
'cert_availability': _('Has a TLS certificate'),
|
||||||
|
}
|
||||||
|
dump = actions.superuser_run('email_server', ['-i', 'tls', 'check'])
|
||||||
|
for jmap in json.loads(dump):
|
||||||
|
results.append(models.Diagnosis.from_json(jmap, translation.get))
|
||||||
|
|
||||||
|
|
||||||
def repair():
|
def repair():
|
||||||
actions.superuser_run('email_server', ['-i', 'tls', 'set_up'])
|
actions.superuser_run('email_server', ['-i', 'tls', 'set_up'])
|
||||||
|
|
||||||
|
|
||||||
def check_tls():
|
def repair_component(action):
|
||||||
diagnosis = models.MainCfDiagnosis('Postfix TLS')
|
action_to_services = {'set_cert': ['dovecot', 'postfix']}
|
||||||
|
if action not in action_to_services: # action not allowed
|
||||||
|
return
|
||||||
|
actions.superuser_run('email_server', ['-i', 'tls', action])
|
||||||
|
return action_to_services[action]
|
||||||
|
|
||||||
|
|
||||||
|
def check_tls(title=''):
|
||||||
|
diagnosis = models.MainCfDiagnosis(title)
|
||||||
diagnosis.compare(postfix_config, postconf.get_many_unsafe)
|
diagnosis.compare(postfix_config, postconf.get_many_unsafe)
|
||||||
return diagnosis
|
return diagnosis
|
||||||
|
|
||||||
@ -102,7 +132,12 @@ def try_set_up_certificates():
|
|||||||
def find_cert_folder() -> str:
|
def find_cert_folder() -> str:
|
||||||
directory = '/etc/letsencrypt/live'
|
directory = '/etc/letsencrypt/live'
|
||||||
domains_available = []
|
domains_available = []
|
||||||
for item in os.listdir(directory):
|
try:
|
||||||
|
listdir_result = os.listdir(directory)
|
||||||
|
except OSError:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
for item in listdir_result:
|
||||||
if item[0] != '.' and os.path.isdir(directory + '/' + item):
|
if item[0] != '.' and os.path.isdir(directory + '/' + item):
|
||||||
domains_available.append(item)
|
domains_available.append(item)
|
||||||
domains_available.sort()
|
domains_available.sort()
|
||||||
@ -129,7 +164,41 @@ def write_dovecot_cert_config(cert, key):
|
|||||||
fd.write(content)
|
fd.write(content)
|
||||||
|
|
||||||
|
|
||||||
|
def check_postfix_cert_usage(title=''):
|
||||||
|
prefix = '/etc/letsencrypt/live/'
|
||||||
|
diagnosis = models.Diagnosis(title, action='set_cert')
|
||||||
|
conf = postconf.get_many_unsafe(['smtpd_tls_cert_file',
|
||||||
|
'smtpd_tls_key_file'])
|
||||||
|
if not conf['smtpd_tls_cert_file'].startswith(prefix):
|
||||||
|
diagnosis.error("Cert file not in Let's Encrypt directory")
|
||||||
|
if not conf['smtpd_tls_key_file'].startswith(prefix):
|
||||||
|
diagnosis.error("Privkey file not in Let's Encrypt directory")
|
||||||
|
|
||||||
|
return diagnosis
|
||||||
|
|
||||||
|
|
||||||
|
def su_check_cert_availability(title=''):
|
||||||
|
diagnosis = models.Diagnosis(title)
|
||||||
|
if find_cert_folder() == '':
|
||||||
|
diagnosis.error("Could not find a Let's Encrypt certificate")
|
||||||
|
return diagnosis
|
||||||
|
|
||||||
|
|
||||||
def action_set_up():
|
def action_set_up():
|
||||||
with postconf.mutex.lock_all():
|
with postconf.mutex.lock_all():
|
||||||
repair_tls(check_tls())
|
repair_tls(check_tls())
|
||||||
try_set_up_certificates()
|
try_set_up_certificates()
|
||||||
|
|
||||||
|
|
||||||
|
def action_set_cert():
|
||||||
|
with postconf.mutex.lock_all():
|
||||||
|
try_set_up_certificates()
|
||||||
|
|
||||||
|
|
||||||
|
def action_check():
|
||||||
|
checks = ('cert_availability',)
|
||||||
|
results = []
|
||||||
|
for check_name in checks:
|
||||||
|
check_function = globals()['su_check_' + check_name]
|
||||||
|
results.append(check_function(check_name).to_json())
|
||||||
|
json.dump(results, sys.stdout, indent=0) # indent=0 adds a new line
|
||||||
|
|||||||
@ -14,5 +14,44 @@
|
|||||||
{% trans "Visit Rspamd administration interface" %}
|
{% trans "Visit Rspamd administration interface" %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
{% if related_diagnostics %}
|
||||||
|
<h3>{% trans "Service Alert" %}</h3>
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for model in related_diagnostics %}
|
||||||
|
<li class="list-group-item clearfix">
|
||||||
|
|
||||||
|
<span>{{ model.title }}</span>
|
||||||
|
{% if model.critical %}
|
||||||
|
<span class="badge badge-danger">{% trans "error" %}</span>
|
||||||
|
{% elif model.errors %}
|
||||||
|
<span class="badge badge-warning">{% trans "failed" %}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge badge-success">{% trans "passed" %}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if model.has_failed and model.action %}
|
||||||
|
<form method="post" class="float-right"
|
||||||
|
action="{{ request.path }}" >
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-primary"
|
||||||
|
name="repair" value="{{ model.action }}">
|
||||||
|
{% trans "Repair" %}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for message in model.critical %}
|
||||||
|
<li>{{ message }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% for message in model.errors %}
|
||||||
|
<li>{{ message }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -3,9 +3,12 @@ import io
|
|||||||
import itertools
|
import itertools
|
||||||
import pwd
|
import pwd
|
||||||
|
|
||||||
|
import plinth.actions
|
||||||
import plinth.utils
|
import plinth.utils
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.http import HttpResponseBadRequest
|
||||||
|
from django.shortcuts import redirect
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.generic.base import TemplateView, View
|
from django.views.generic.base import TemplateView, View
|
||||||
@ -82,6 +85,57 @@ class EmailServerView(TabMixin, AppView):
|
|||||||
"""Server configuration page"""
|
"""Server configuration page"""
|
||||||
app_id = 'email_server'
|
app_id = 'email_server'
|
||||||
template_name = 'email_server.html'
|
template_name = 'email_server.html'
|
||||||
|
audit_modules = ('tls', 'rcube')
|
||||||
|
|
||||||
|
def get_context_data(self, *args, **kwargs):
|
||||||
|
dlist = []
|
||||||
|
for module_name in self.audit_modules:
|
||||||
|
self._get_audit_results(module_name, dlist)
|
||||||
|
dlist.sort(key=audit.models.Diagnosis.sorting_key)
|
||||||
|
|
||||||
|
context = super().get_context_data(*args, **kwargs)
|
||||||
|
context['related_diagnostics'] = dlist
|
||||||
|
return context
|
||||||
|
|
||||||
|
def _get_audit_results(self, module_name, dlist):
|
||||||
|
try:
|
||||||
|
results = getattr(audit, module_name).get()
|
||||||
|
except Exception as e:
|
||||||
|
title = _('Internal error in {0}').format('audit.' + module_name)
|
||||||
|
diagnosis = audit.models.Diagnosis(title)
|
||||||
|
diagnosis.critical(str(e))
|
||||||
|
diagnosis.critical(_('Check syslog for more information'))
|
||||||
|
results = [diagnosis]
|
||||||
|
|
||||||
|
for diagnosis in results:
|
||||||
|
if diagnosis.action:
|
||||||
|
diagnosis.action = '%s.%s' % (module_name, diagnosis.action)
|
||||||
|
if diagnosis.has_failed:
|
||||||
|
dlist.append(diagnosis)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
repair_field = request.POST.get('repair')
|
||||||
|
module_name, sep, action_name = repair_field.partition('.')
|
||||||
|
if not sep or module_name not in self.audit_modules:
|
||||||
|
return HttpResponseBadRequest('Bad post data')
|
||||||
|
|
||||||
|
self._repair(module_name, action_name)
|
||||||
|
return redirect(request.path)
|
||||||
|
|
||||||
|
def _repair(self, module_name, action_name):
|
||||||
|
module = getattr(audit, module_name)
|
||||||
|
if not hasattr(module, 'repair_component'):
|
||||||
|
return
|
||||||
|
|
||||||
|
reload_list = []
|
||||||
|
try:
|
||||||
|
reload_list = module.repair_component(action_name)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for service in reload_list:
|
||||||
|
# plinth.action_utils.service_reload(service)
|
||||||
|
plinth.actions.superuser_run('service', ['reload', service])
|
||||||
|
|
||||||
|
|
||||||
class MyMailView(TabMixin, TemplateView):
|
class MyMailView(TabMixin, TemplateView):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user