diff --git a/TODO.md b/TODO.md index a5515169..135d1726 100644 --- a/TODO.md +++ b/TODO.md @@ -430,11 +430,10 @@ mkhomedir_helper or create ssh homes with bash.rc and such # Automatically re-run backends until success? only timedout executions? # TODO save serialized versions ob backendoperation.instance in order to allow backend reexecution of deleted objects - # upgrade to django 1.9 and make margins wider # lets encrypt: DNS vs HTTP challange # lets enctypt: autorenew -# lets encrypt: websites without / content # Warning websites with ssl options without https protocol +# Schedule cancellation diff --git a/orchestra/contrib/accounts/admin.py b/orchestra/contrib/accounts/admin.py index aa20c8ba..5abb40d7 100644 --- a/orchestra/contrib/accounts/admin.py +++ b/orchestra/contrib/accounts/admin.py @@ -202,10 +202,14 @@ class AccountAdminMixin(object): except KeyError: pass else: - help_text = ( - "Designates whether this account should be treated as active. " - "Unselect this instead of deleting accounts." - ) + opts = self.model._meta + help_text = _( + "Designates whether this %(name)s should be treated as active. " + "Unselect this instead of deleting %(plural_name)s." + ) % { + 'name': opts.verbose_name, + 'plural_name': opts.verbose_name_plural, + } if obj and not obj.account.is_active: help_text += "
This user's account is dissabled" field.help_text = _(help_text) diff --git a/orchestra/contrib/domains/admin.py b/orchestra/contrib/domains/admin.py index 33b187ef..25e799fa 100644 --- a/orchestra/contrib/domains/admin.py +++ b/orchestra/contrib/domains/admin.py @@ -95,14 +95,11 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin): return '
'.join(links) add_url = reverse('admin:websites_website_add') add_url += '?account=%i&domains=%i' % (domain.account_id, domain.pk) - context = { - 'title': _("Add website"), - 'url': add_url, - 'image': '' % static('orchestra/images/add.png'), - } - add_link = '%(image)s' % context - site_link = get_on_site_link('http://%s' % domain.name) - return _("No website %s %s") % (add_link, site_link) + image = '' % static('orchestra/images/add.png') + add_link = '%s' % ( + add_url, _("Add website"), image + ) + return _("No website %s") % (add_link) display_websites.admin_order_field = 'websites__name' display_websites.short_description = _("Websites") display_websites.allow_tags = True diff --git a/orchestra/contrib/letsencrypt/actions.py b/orchestra/contrib/letsencrypt/actions.py index d5672da8..a4d6ce8a 100644 --- a/orchestra/contrib/letsencrypt/actions.py +++ b/orchestra/contrib/letsencrypt/actions.py @@ -1,8 +1,9 @@ from django.contrib import messages, admin from django.template.response import TemplateResponse from django.utils.safestring import mark_safe -from django.utils.translation import ungettext, ugettext_lazy as _ +from django.utils.translation import ungettext, ugettext, ugettext_lazy as _ +from orchestra.admin.utils import admin_link from orchestra.contrib.orchestration import Operation, helpers from .helpers import is_valid_domain, read_live_lineages, configure_cert @@ -12,6 +13,18 @@ from .forms import LetsEncryptForm def letsencrypt(modeladmin, request, queryset): wildcards = set() domains = set() + content_error = '' + contentless = queryset.exclude(content__path='/').distinct() + if contentless: + content_error = ungettext( + ugettext("Selected website %s doesn't have a webapp mounted on /."), + ugettext("Selected websites %s don't have a webapp mounted on /."), + len(contentless), + ) + content_error += ugettext("
Websites need a webapp (e.g. static) mounted on / " + "for let's encrypt HTTP-01 challenge to work.") + content_error = content_error % ', '.join((admin_link()(website) for website in contentless)) + content_error = '' % content_error queryset = queryset.prefetch_related('domains') for website in queryset: for domain in website.domains.all(): @@ -23,7 +36,7 @@ def letsencrypt(modeladmin, request, queryset): action_value = 'letsencrypt' if request.POST.get('post') == 'generic_confirmation': form = LetsEncryptForm(domains, wildcards, request.POST) - if form.is_valid(): + if not content_error and form.is_valid(): cleaned_data = form.cleaned_data domains = set(cleaned_data['domains']) operations = [] @@ -86,10 +99,10 @@ def letsencrypt(modeladmin, request, queryset): context = { 'title': _("Let's encrypt!"), 'action_name': _("Encrypt"), - 'content_message': _("You are going to request certificates for the following domains.
" + 'content_message': ugettext("You are going to request certificates for the following domains.
" "This operation is safe to run multiple times, " "existing certificates will not be regenerated. " - "Also notice that let's encrypt does not currently support wildcard certificates."), + "Also notice that let's encrypt does not currently support wildcard certificates.") + content_error, 'action_value': action_value, 'queryset': queryset, 'opts': opts, diff --git a/orchestra/contrib/letsencrypt/backends.py b/orchestra/contrib/letsencrypt/backends.py index d5599a22..a36b3443 100644 --- a/orchestra/contrib/letsencrypt/backends.py +++ b/orchestra/contrib/letsencrypt/backends.py @@ -45,10 +45,7 @@ class LetsEncryptController(ServiceController): super().commit() def get_context(self, website): - try: - content = website.content_set.get(path='/') - except website.content_set.model.DoesNotExist: - raise + content = website.content_set.get(path='/') return { 'letsencrypt_auto': settings.LETSENCRYPT_AUTO_PATH, 'webroot': content.webapp.get_path(), diff --git a/orchestra/contrib/orchestration/helpers.py b/orchestra/contrib/orchestration/helpers.py index fb8da5cc..430772f1 100644 --- a/orchestra/contrib/orchestration/helpers.py +++ b/orchestra/contrib/orchestration/helpers.py @@ -128,7 +128,7 @@ def message_user(request, logs): async) if errors: if total == 1: - msg = _('{name} has fail to execute'), + msg = _('{name} has fail to execute') else: msg = ungettext( _('{errors} out of {total} backends has fail to execute'),