Random fixes

This commit is contained in:
Marc Aymerich 2015-10-08 13:54:39 +00:00
parent e4edb89d2c
commit 38a46b5983
18 changed files with 305 additions and 149 deletions

View File

@ -423,4 +423,5 @@ mkhomedir_helper or create ssh homes with bash.rc and such
# account contacts inline, show provided fields and ignore the rest?
# email usage -webkit-column-count:3;-moz-column-count:3;column-count:3;
# Protect fucking search url and put into /admin/search and admin.py
# wordpressmu custom_url: set blog.domain

View File

@ -39,24 +39,56 @@ def get_urls():
admin.site.get_urls = get_urls
def get_model(model_name, model_name_map):
try:
return model_name_map[model_name.lower()]
except KeyError:
return
def search(request):
query = request.GET.get('q', '')
if query.endswith('!'):
from ..contrib.accounts.models import Account
search_term = query
models = set()
selected_models = set()
model_name_map = {}
for service in itertools.chain(services, accounts):
if service.search:
models.add(service.model)
model_name_map[service.model._meta.model_name] = service.model
# Account direct access
query = query.replace('!', '')
if search_term.endswith('!'):
from ..contrib.accounts.models import Account
search_term = search_term.replace('!', '')
try:
account = Account.objects.get(username=query)
account = Account.objects.get(username=search_term)
except Account.DoesNotExist:
pass
else:
account_url = reverse('admin:accounts_account_change', args=(account.pk,))
return redirect(account_url)
# Search for specific model
elif ':' in search_term:
new_search_term = []
for part in search_term.split():
if ':' in part:
model_name, term = part.split(':')
model = get_model(model_name, model_name_map)
# Retry with singular version
if model is None and model_name.endswith('s'):
model = get_model(model_name[:-1], model_name_map)
if model is None:
new_search_term.append(':'.join((model_name, term)))
else:
selected_models.add(model)
new_search_term.append(term)
else:
new_search_term.append(part)
search_term = ' '.join(new_search_term)
if selected_models:
models = selected_models
results = OrderedDict()
models = set()
for service in itertools.chain(services, accounts):
if service.search:
models.add(service.model)
models = sorted(models, key=lambda m: m._meta.verbose_name_plural.lower())
total = 0
for model in models:
@ -66,7 +98,7 @@ def search(request):
pass
else:
qs = modeladmin.get_queryset(request)
qs, search_use_distinct = modeladmin.get_search_results(request, qs, query)
qs, search_use_distinct = modeladmin.get_search_results(request, qs, search_term)
if search_use_distinct:
qs = qs.distinct()
num = len(qs)
@ -79,6 +111,7 @@ def search(request):
'total': total,
'columns': min(int(total/17), 3),
'query': query,
'search_term': search_term,
'results': results,
'search_autofocus': True,
}

View File

@ -80,17 +80,24 @@ class EnhaceSearchMixin(object):
def get_search_results(self, request, queryset, search_term):
""" allows to specify field <field_name>:<search_term> """
search_fields = self.get_search_fields(request)
if ':' in search_term:
if '=' in search_term:
fields = {field.split('__')[0]: field for field in search_fields}
new_search_term = []
for part in search_term.split():
cur_search_term = ''
for field, term in pairwise(part.split(':')):
field = None
if '=' in part:
field, term = part.split('=')
kwarg = '%s__icontains'
c_term = term
if term.startswith(('"', "'")) and term.endswith(('"', "'")):
c_term = term[1:-1]
kwarg = '%s__iexact'
if field in fields:
queryset = queryset.filter(**{'%s__icontains' % fields[field]: term})
queryset = queryset.filter(**{kwarg % fields[field]: c_term})
else:
cur_search_term += ':'.join((field, term))
new_search_term.append(cur_search_term)
new_search_term.append('='.join((field, term)))
else:
new_search_term.append(part)
search_term = ' '.join(new_search_term)
return super(EnhaceSearchMixin, self).get_search_results(request, queryset, search_term)

View File

@ -538,7 +538,7 @@ msgstr ""
#: templates/bills/microspective.html:149
msgid "QUESTIONS"
msgstr ""
msgstr "PREGUNTAS"
#: templates/bills/microspective.html:150
#, python-format

View File

@ -330,7 +330,7 @@ class Bill(models.Model):
subtotals[tax] = total
result = {}
for tax, subtotal in subtotals.items():
result[tax] = (subtotal, round(tax/100*subtotal, 2))
result[tax] = [subtotal, round(tax/100*subtotal, 2)]
return result
@lru_cache()

View File

@ -127,13 +127,30 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
if not add:
self.check_unrelated_address(request, obj)
self.check_matching_address(request, obj)
return super(MailboxAdmin, self).render_change_form(
request, context, add, change, form_url, obj)
def log_addition(self, request, object):
self.check_unrelated_address(request, object)
self.check_matching_address(request, object)
return super(MailboxAdmin, self).log_addition(request, object)
def check_matching_address(self, request, obj):
local_domain = settings.MAILBOXES_LOCAL_DOMAIN
if obj.name and local_domain:
try:
addr = Address.objects.get(
name=obj.name, domain__name=local_domain, account_id=self.account.pk)
except Address.DoesNotExist:
pass
else:
if addr not in obj.addresses.all():
msg = _("Mailbox '%s' local address matches '%s', please consider if "
"selecting it makes sense.") % (obj, addr)
if msg not in (m.message for m in messages.get_messages(request)):
self.message_user(request, msg, level=messages.WARNING)
def check_unrelated_address(self, request, obj):
# Check if there exists an unrelated local Address for this mbox
local_domain = settings.MAILBOXES_LOCAL_DOMAIN
@ -169,7 +186,9 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
fields = ('account_link', 'email_link', 'mailboxes', 'forward')
add_fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward')
# inlines = [AutoresponseInline]
search_fields = ('forward', 'mailboxes__name', 'account__username', 'computed_email')
search_fields = (
'forward', 'mailboxes__name', 'account__username', 'computed_email', 'domain__name'
)
readonly_fields = ('account_link', 'domain_link', 'email_link')
actions = (SendAddressEmail(),)
filter_by_account_fields = ('domain', 'mailboxes')
@ -224,6 +243,29 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
qs = super(AddressAdmin, self).get_queryset(request)
return qs.annotate(computed_email=Concat(F('name'), V('@'), F('domain__name')))
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
if not add:
self.check_matching_mailbox(request, obj)
return super(AddressAdmin, self).render_change_form(
request, context, add, change, form_url, obj)
def log_addition(self, request, object):
self.check_matching_mailbox(request, object)
return super(AddressAdmin, self).log_addition(request, object)
def check_matching_mailbox(self, request, obj):
# Check if new addresse matches with a mbox because of having a local domain
if obj.name and obj.domain and obj.domain.name == settings.MAILBOXES_LOCAL_DOMAIN:
if obj.name not in obj.forward.split() and Mailbox.objects.filter(name=obj.name).exists():
for mailbox in obj.mailboxes.all():
if mailbox.name == obj.name:
return
msg = _("Address '%s' matches mailbox '%s' local address, please consider "
"if makes sense adding the mailbox on the mailboxes or forward field."
) % (obj, obj.name)
if msg not in (m.message for m in messages.get_messages(request)):
self.message_user(request, msg, level=messages.WARNING)
admin.site.register(Mailbox, MailboxAdmin)
admin.site.register(Address, AddressAdmin)

View File

@ -45,24 +45,6 @@ class MailboxForm(forms.ModelForm):
if self.instance and self.instance.pk:
self.fields['addresses'].initial = self.instance.addresses.all()
def clean(self):
cleaned_data = super(MailboxForm, self).clean()
name = self.instance.name if self.instance.pk else cleaned_data.get('name')
local_domain = settings.MAILBOXES_LOCAL_DOMAIN
if name and local_domain:
try:
addr = Address.objects.get(
name=name, domain__name=local_domain, account_id=self.modeladmin.account.pk)
except Address.DoesNotExist:
pass
else:
if addr not in cleaned_data.get('addresses', []):
raise ValidationError({
'addresses': _("This mailbox local address matche '%s', "
"please make explicit this fact by selecting it.") % addr
})
return cleaned_data
class MailboxChangeForm(UserChangeForm, MailboxForm):
pass
@ -86,20 +68,3 @@ class AddressForm(forms.ModelForm):
forward = cleaned_data.get('forward', '')
if not cleaned_data.get('mailboxes', True) and not forward:
raise ValidationError(_("Mailboxes or forward address should be provided."))
# Check if new addresse matches with a mbox because of having a local domain
if self.instance.pk:
name = self.instance.name
domain = self.instance.domain
else:
name = cleaned_data.get('name')
domain = cleaned_data.get('domain')
if domain and name and domain.name == settings.MAILBOXES_LOCAL_DOMAIN:
if name not in forward.split() and Mailbox.objects.filter(name=name).exists():
for mailbox in cleaned_data.get('mailboxes', []):
if mailbox.name == name:
return
raise ValidationError(
_("This address matches mailbox '%s' local address, please make explicit "
"this fact by adding the mailbox on the mailboxes or forward field.") % name
)
return cleaned_data

View File

@ -103,7 +103,7 @@ def OpenSSH(backend, log, server, cmds, async=False):
script = '\n'.join(cmds)
script = script.replace('\r', '')
log.state = log.STARTED
log.script = script
log.script = '\n'.join((log.script, script))
log.save(update_fields=('script', 'state', 'updated_at'))
if not cmds:
return
@ -116,12 +116,14 @@ def OpenSSH(backend, log, server, cmds, async=False):
log.stdout += state.stdout.decode('utf8')
log.stderr += state.stderr.decode('utf8')
log.save(update_fields=('stdout', 'stderr', 'updated_at'))
log.exit_code = state.exit_code
exit_code = state.exit_code
else:
log.stdout = ssh.stdout.decode('utf8')
log.stderr = ssh.stderr.decode('utf8')
log.exit_code = ssh.exit_code
log.state = log.SUCCESS if log.exit_code == 0 else log.FAILURE
log.stdout += ssh.stdout.decode('utf8')
log.stderr += ssh.stderr.decode('utf8')
exit_code = ssh.exit_code
if not log.exit_code:
log.exit_code = exit_code
log.state = log.SUCCESS if exit_code == 0 else log.FAILURE
logger.debug('%s execution state on %s is %s' % (backend, server, log.state))
log.save()
except:
@ -164,10 +166,11 @@ def Python(backend, log, server, cmds, async=False):
except:
log.exit_code = 1
log.state = log.FAILURE
log.stdout = '\n'.join(stdout)
log.traceback = ExceptionInfo(sys.exc_info()).traceback
log.stdout += '\n'.join(stdout)
log.traceback += ExceptionInfo(sys.exc_info()).traceback
logger.error('Exception while executing %s on %s' % (backend, server))
else:
if not log.exit_code:
log.exit_code = 0
log.state = log.SUCCESS
logger.debug('%s execution state on %s is %s' % (backend, server, log.state))

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-15 12:08+0000\n"
"POT-Creation-Date: 2015-10-08 11:53+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -52,7 +52,7 @@ msgstr ""
msgid "Process"
msgstr ""
#: actions.py:63 actions.py:134 models.py:97 models.py:164
#: actions.py:63 actions.py:134 models.py:97 models.py:172
msgid "Executed"
msgstr ""
@ -112,7 +112,7 @@ msgstr ""
msgid "%s selected processes have been marked as executed."
msgstr ""
#: actions.py:150 models.py:165
#: actions.py:150 models.py:173
msgid "Aborted"
msgstr ""
@ -133,15 +133,19 @@ msgstr ""
msgid "Commit"
msgstr ""
#: admin.py:43
#: admin.py:44
msgid "ID"
msgstr ""
#: admin.py:105
#: admin.py:106
msgid "proc"
msgstr ""
#: admin.py:158
#: admin.py:129 templates/admin/payments/transaction/report.html:62
msgid "State"
msgstr ""
#: admin.py:168
msgid "Transactions"
msgstr ""
@ -186,6 +190,18 @@ msgstr ""
msgid "SEPA Direct Debit"
msgstr ""
#: methods/sepadirectdebit.py:47
msgid ""
"The transaction is created and requires the generation of the SEPA direct "
"debit XML file."
msgstr ""
#: methods/sepadirectdebit.py:49
msgid ""
"SEPA Direct Debit XML file is generated but needs to be sent to the "
"financial institution."
msgstr ""
#: models.py:20
msgid "account"
msgstr ""
@ -194,7 +210,7 @@ msgstr ""
msgid "method"
msgstr ""
#: models.py:24 models.py:169
#: models.py:24 models.py:177
msgid "data"
msgstr ""
@ -211,68 +227,90 @@ msgid "Waitting execution"
msgstr ""
#: models.py:102
msgid "bill"
msgid ""
"The transaction is created and requires processing by the specific payment "
"method."
msgstr ""
#: models.py:105
msgid "source"
#: models.py:104
msgid ""
"The transaction is processed and its pending execution on the related "
"financial institution."
msgstr ""
#: models.py:106
msgid "The transaction is executed on the financial institution."
msgstr ""
#: models.py:107
msgid "The transaction ammount is secured."
msgstr ""
#: models.py:108
msgid ""
"The transaction has failed and the ammount is lost, a new transaction should "
"be created for recharging."
msgstr ""
#: models.py:112
msgid "bill"
msgstr ""
#: models.py:115
msgid "source"
msgstr ""
#: models.py:117
msgid "process"
msgstr ""
#: models.py:108 models.py:171
#: models.py:118 models.py:179
msgid "state"
msgstr ""
#: models.py:110
#: models.py:120
msgid "amount"
msgstr ""
#: models.py:112 models.py:172
#: models.py:122 models.py:180
msgid "created"
msgstr ""
#: models.py:113
#: models.py:123
msgid "modified"
msgstr ""
#: models.py:128
#: models.py:138
msgid "New transactions can not be allocated for this bill."
msgstr ""
#: models.py:163 templates/admin/payments/transaction/report.html:63
#: models.py:171 templates/admin/payments/transaction/report.html:63
msgid "Created"
msgstr ""
#: models.py:166
#: models.py:174
msgid "Commited"
msgstr ""
#: models.py:170
#: models.py:178
msgid "file"
msgstr ""
#: models.py:173
#: models.py:181
msgid "updated"
msgstr ""
#: models.py:176
#: models.py:184
msgid "Transaction processes"
msgstr ""
#: settings.py:12
#, fuzzy, python-format
#| msgid ""
#| "This bill will be automatically charged to your bank account with IBAN "
#| "number<br><strong>%s</strong>."
#: settings.py:14
msgid ""
"<strong>Direct debit</strong>, this bill will be automatically charged to "
"your bank account with IBAN number<br><strong>%(number)s</strong>."
msgstr ""
"<strong>Càrrec per domiciliació</strong>, aquesta factura es cobrarà "
"automaticament en el teu compte bancari amb IBAN <br><strong>%s</strong>."
"automaticament en el teu compte bancari amb IBAN <br><strong>%(number)s</strong>."
#: templates/admin/payments/transaction/report.html:38
msgid "Summary"
@ -299,10 +337,6 @@ msgstr ""
msgid "Contact"
msgstr ""
#: templates/admin/payments/transaction/report.html:62
msgid "State"
msgstr ""
#: templates/admin/payments/transaction/report.html:64
msgid "Updated"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-15 12:08+0000\n"
"POT-Creation-Date: 2015-10-08 12:14+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -52,7 +52,7 @@ msgstr ""
msgid "Process"
msgstr ""
#: actions.py:63 actions.py:134 models.py:97 models.py:164
#: actions.py:63 actions.py:134 models.py:97 models.py:172
msgid "Executed"
msgstr ""
@ -112,7 +112,7 @@ msgstr ""
msgid "%s selected processes have been marked as executed."
msgstr ""
#: actions.py:150 models.py:165
#: actions.py:150 models.py:173
msgid "Aborted"
msgstr ""
@ -133,15 +133,19 @@ msgstr ""
msgid "Commit"
msgstr ""
#: admin.py:43
#: admin.py:44
msgid "ID"
msgstr ""
#: admin.py:105
#: admin.py:106
msgid "proc"
msgstr ""
#: admin.py:158
#: admin.py:129 templates/admin/payments/transaction/report.html:62
msgid "State"
msgstr ""
#: admin.py:168
msgid "Transactions"
msgstr ""
@ -186,6 +190,18 @@ msgstr ""
msgid "SEPA Direct Debit"
msgstr ""
#: methods/sepadirectdebit.py:47
msgid ""
"The transaction is created and requires the generation of the SEPA direct "
"debit XML file."
msgstr ""
#: methods/sepadirectdebit.py:49
msgid ""
"SEPA Direct Debit XML file is generated but needs to be sent to the "
"financial institution."
msgstr ""
#: models.py:20
msgid "account"
msgstr ""
@ -194,7 +210,7 @@ msgstr ""
msgid "method"
msgstr ""
#: models.py:24 models.py:169
#: models.py:24 models.py:177
msgid "data"
msgstr ""
@ -211,68 +227,90 @@ msgid "Waitting execution"
msgstr ""
#: models.py:102
msgid "bill"
msgid ""
"The transaction is created and requires processing by the specific payment "
"method."
msgstr ""
#: models.py:105
msgid "source"
#: models.py:104
msgid ""
"The transaction is processed and its pending execution on the related "
"financial institution."
msgstr ""
#: models.py:106
msgid "The transaction is executed on the financial institution."
msgstr ""
#: models.py:107
msgid "The transaction ammount is secured."
msgstr ""
#: models.py:108
msgid ""
"The transaction has failed and the ammount is lost, a new transaction should "
"be created for recharging."
msgstr ""
#: models.py:112
msgid "bill"
msgstr ""
#: models.py:115
msgid "source"
msgstr ""
#: models.py:117
msgid "process"
msgstr ""
#: models.py:108 models.py:171
#: models.py:118 models.py:179
msgid "state"
msgstr ""
#: models.py:110
#: models.py:120
msgid "amount"
msgstr ""
#: models.py:112 models.py:172
#: models.py:122 models.py:180
msgid "created"
msgstr ""
#: models.py:113
#: models.py:123
msgid "modified"
msgstr ""
#: models.py:128
#: models.py:138
msgid "New transactions can not be allocated for this bill."
msgstr ""
#: models.py:163 templates/admin/payments/transaction/report.html:63
#: models.py:171 templates/admin/payments/transaction/report.html:63
msgid "Created"
msgstr ""
#: models.py:166
#: models.py:174
msgid "Commited"
msgstr ""
#: models.py:170
#: models.py:178
msgid "file"
msgstr ""
#: models.py:173
#: models.py:181
msgid "updated"
msgstr ""
#: models.py:176
#: models.py:184
msgid "Transaction processes"
msgstr ""
#: settings.py:12
#, fuzzy, python-format
#| msgid ""
#| "This bill will be automatically charged to your bank account with IBAN "
#| "number<br><strong>%s</strong>."
#: settings.py:14
msgid ""
"<strong>Direct debit</strong>, this bill will be automatically charged to "
"your bank account with IBAN number<br><strong>%(number)s</strong>."
msgstr ""
"<strong>Adeudo por domiciliación</strong>, esta factura se cobrará "
"automaticamente en tu cuenta bancaria con IBAN <br><strong>%s</strong>."
"automaticamente en tu cuenta bancaria con IBAN <br><strong>%(number)s</strong>."
#: templates/admin/payments/transaction/report.html:38
msgid "Summary"
@ -299,10 +337,6 @@ msgstr ""
msgid "Contact"
msgstr ""
#: templates/admin/payments/transaction/report.html:62
msgid "State"
msgstr ""
#: templates/admin/payments/transaction/report.html:64
msgid "Updated"
msgstr ""

View File

@ -1,4 +1,5 @@
import re
import sys
import textwrap
from urllib.parse import urlparse
@ -46,6 +47,7 @@ class WordpressMuBackend(ServiceController):
raise RuntimeError(errors[0] if errors else 'Unknown %i error' % response.status_code)
def get_id(self, session, saas):
blog_id = saas.data.get('blog_id')
search = self.get_main_url()
search += '/wp-admin/network/sites.php?s=%s&action=blogs' % saas.name
regex = re.compile(
@ -55,23 +57,31 @@ class WordpressMuBackend(ServiceController):
content = session.get(search).content.decode('utf8')
# Get id
ids = regex.search(content)
if not ids:
if not ids and not blog_id:
raise RuntimeError("Blog '%s' not found" % saas.name)
if ids:
ids = ids.groups()
if len(ids) > 1:
if len(ids) > 1 and not blog_id:
raise ValueError("Multiple matches")
# Get wpnonce
try:
wpnonce = re.search(r'<span class="delete">(.*)</span>', content).groups()[0]
except TypeError:
# No search results, try some luck
wpnonce = content
wpnonce = re.search(r'_wpnonce=([^"]*)"', wpnonce).groups()[0]
return int(ids[0]), wpnonce
return blog_id or int(ids[0]), wpnonce
def create_blog(self, saas, server):
if saas.data.get('blog_id'):
return
session = requests.Session()
self.login(session)
# Check if blog already exists
try:
self.get_id(session, saas)
blog_id, wpnonce = self.get_id(session, saas)
except RuntimeError:
url = self.get_main_url()
url += '/wp-admin/network/site-new.php'
@ -91,6 +101,16 @@ class WordpressMuBackend(ServiceController):
# Validate response
response = session.post(url, data=data)
self.validate_response(response)
blog_id = re.compile(r'<link id="wp-admin-canonical" rel="canonical" href="http(?:[^ ]+)/wp-admin/network/site-new.php\?id=([0-9]+)" />')
content = response.content.decode('utf8')
blog_id = blog_id.search(content).groups()[0]
sys.stdout.write("Created blog ID: %s\n" % blog_id)
saas.data['blog_id'] = int(blog_id)
saas.save(update_fields=('data',))
else:
sys.stdout.write("Retrieved blog ID: %s\n" % blog_id)
saas.data['blog_id'] = int(blog_id)
saas.save(update_fields=('data',))
def delete_blog(self, saas, server):
session = requests.Session()
@ -122,32 +142,37 @@ class WordpressMuBackend(ServiceController):
def save(self, saas):
self.append(self.create_blog, saas)
context = self.get_context(saas)
context['IDENT'] = "b.domain = '%(domain)s'" % context
if context['blog_id']:
context['IDENT'] = "b.blog_id = '%(blog_id)s'" % context
self.append(textwrap.dedent("""
# Update custom URL mapping
existing=( $(mysql -Nrs %(db_name)s --execute='
existing=( $(mysql -Nrs %(db_name)s --execute="
SELECT b.blog_id, b.domain, m.domain, b.path
FROM wp_domain_mapping AS m, wp_blogs AS b
WHERE m.blog_id = b.blog_id AND m.active AND b.domain = "%(domain)s";') )
WHERE m.blog_id = b.blog_id AND m.active AND %(IDENT)s;") )
if [[ ${existing[0]} != '' ]]; then
# Clear custom domain
if [[ "%(custom_domain)s" == "" ]]; then
mysql %(db_name)s --execute="
DELETE wp_domain_mapping AS m, wp_blogs AS b
WHERE m.blog_id = b.blog_id AND m.active AND b.domain = '%(domain)s';
DELETE FROM m
USING wp_domain_mapping AS m, wp_blogs AS b
WHERE m.blog_id = b.blog_id AND m.active AND %(IDENT)s';
UPDATE wp_blogs
SET path='/'
WHERE blog_id=${existing[0]};"
elif [[ "${existing[2]}" != "%(custom_domain)s" || "${existing[3]}" != "%(custom_path)s" ]]; then
mysql %(db_name)s --execute='
mysql %(db_name)s --execute="
UPDATE wp_domain_mapping as m, wp_blogs as b
SET m.domain = "%(custom_domain)s", b.path = "%(custom_path)s"
WHERE m.blog_id = b.blog_id AND m.active AND b.domain = "%(domain)s";'
SET m.domain = '%(custom_domain)s', b.path = '%(custom_path)s'
WHERE m.blog_id = b.blog_id AND m.active AND %(IDENT)s';"
fi
else
blog=( $(mysql -Nrs %(db_name)s --execute='
SELECT blog_id, path FROM wp_blogs WHERE domain = "%(domain)s";') )
mysql %(db_name)s --execute='
elif [[ "%(custom_domain)s" != "" ]]; then
blog=( $(mysql -Nrs %(db_name)s --execute="
SELECT blog_id, path FROM wp_blogs WHERE domain = '%(domain)s';") )
mysql %(db_name)s --execute="
INSERT INTO wp_domain_mapping
VALUES (blog_id, domain, active) ($blog_id, "%(custom_domain)s", 1);'
(blog_id, domain, active) VALUES (${blog[0]}, '%(custom_domain)s', 1);"
if [[ "${blog[1]}" != "%(custom_path)s" ]]; then
mysql %(db_name)s --execute="
UPDATE wp_blogs
@ -165,6 +190,9 @@ class WordpressMuBackend(ServiceController):
context = {
'db_name': settings.SAAS_WORDPRESS_DB_NAME,
'domain': domain,
'custom_domain': '',
'custom_path': '/',
'blog_id': saas.data.get('blog_id', ''),
}
if saas.custom_url:
custom_url = urlparse(saas.custom_url)

View File

@ -113,12 +113,14 @@ class SoftwareService(plugins.Plugin):
return helpers.create_or_update_directive(self)
def delete_directive(self):
directive = None
try:
old = type(self.instance).objects.get(pk=self.instance.pk)
if old.custom_url:
directive = self.get_directive(old)
except ObjectDoesNotExist:
pass
else:
return
if directive is not None:
directive.delete()
def save(self):

View File

@ -3,6 +3,8 @@ from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from orchestra.forms import widgets
from .options import SoftwareService
from .. import settings
from ..forms import SaaSBaseForm
@ -12,6 +14,8 @@ class WordPressForm(SaaSBaseForm):
email = forms.EmailField(label=_("Email"), widget=forms.TextInput(attrs={'size':'40'}),
help_text=_("A new user will be created if the above email address is not in the database.<br>"
"The username and password will be mailed to this email address."))
blog_id = forms.IntegerField(label=("Blog ID"), widget=widgets.SpanWidget, required=False,
help_text=_("ID of this user on the GitLab server, the only attribute that not changes."))
def __init__(self, *args, **kwargs):
super(WordPressForm, self).__init__(*args, **kwargs)
@ -23,6 +27,7 @@ class WordPressForm(SaaSBaseForm):
class WordPressDataSerializer(serializers.Serializer):
email = serializers.EmailField(label=_("Email"))
blog_id = serializers.IntegerField(label=_("Blog ID"), required=False)
class WordPressService(SoftwareService):
@ -31,6 +36,6 @@ class WordPressService(SoftwareService):
form = WordPressForm
serializer = WordPressDataSerializer
icon = 'orchestra/icons/apps/WordPress.png'
change_readonly_fileds = ('email',)
change_readonly_fileds = ('email', 'blog_id')
site_domain = settings.SAAS_WORDPRESS_DOMAIN
allow_custom_url = settings.SAAS_WORDPRESS_ALLOW_CUSTOM_URL

View File

@ -53,7 +53,9 @@
<input type="text" id="searchbox" style="margin-left:15px;margin-top:7px;" name="q"
placeholder="Search" size="25" value="{{ query }}"
{% if search_autofocus or app_list %}autofocus="autofocus"{% endif %}
title="Use 'username!' for account direct access.">
title="Use 'accountname!' for account direct access
Use 'service:word' for searching on specific services
Use 'fieldname=word' for searching on specific fields">
</form>
<span style="float:right;color:grey;margin:10px;font-size:11px;">
{% url 'admin:accounts_account_change' user.pk as user_change_url %}

View File

@ -7,7 +7,7 @@
<div>
<div style="margin:20px;-webkit-column-count:{{ columns }};-moz-column-count:{{ columns }};column-count:{{ columns }};">
{% for opts, qs in results.items %}
<h3><a href="{% url opts|admin_urlname:'changelist' %}?q={{ query }}">{{ opts.verbose_name_plural|capfirst }}</a>
<h3><a href="{% url opts|admin_urlname:'changelist' %}?q={{ search_term }}">{{ opts.verbose_name_plural|capfirst }}</a>
<span style="font-size:11px"> {{ qs|length }} results</span></h3>
<ul>
{% for instance in qs %}