diff --git a/TODO.md b/TODO.md
index ac85f71e..8303ec77 100644
--- a/TODO.md
+++ b/TODO.md
@@ -423,4 +423,4 @@ 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;
-# resources on service report
+# Protect fucking search url and put into /admin/search and admin.py
diff --git a/orchestra/admin/__init__.py b/orchestra/admin/__init__.py
index b61f7980..49d603ab 100644
--- a/orchestra/admin/__init__.py
+++ b/orchestra/admin/__init__.py
@@ -1,9 +1,16 @@
+import itertools
+from collections import OrderedDict
from functools import update_wrapper
from django.contrib import admin
+from django.core.urlresolvers import reverse
+from django.shortcuts import render, redirect
+from django.utils.safestring import mark_safe
+from django.utils.translation import ugettext_lazy as _
from .dashboard import *
from .options import *
+from ..core import accounts, services
# monkey-patch admin.site in order to porvide some extra admin urls
@@ -30,3 +37,52 @@ def get_urls():
)
return site_get_urls() + extra_patterns
admin.site.get_urls = get_urls
+
+
+def search(request):
+ query = request.GET.get('q', '')
+ if query.endswith('!'):
+ from ..contrib.accounts.models import Account
+ # Account direct access
+ query = query.replace('!', '')
+ try:
+ account = Account.objects.get(username=query)
+ except Account.DoesNotExist:
+ pass
+ else:
+ account_url = reverse('admin:accounts_account_change', args=(account.pk,))
+ return redirect(account_url)
+ 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:
+ try:
+ modeladmin = admin.site._registry[model]
+ except KeyError:
+ pass
+ else:
+ qs = modeladmin.get_queryset(request)
+ qs, search_use_distinct = modeladmin.get_search_results(request, qs, query)
+ if search_use_distinct:
+ qs = qs.distinct()
+ num = len(qs)
+ if num:
+ total += num
+ results[model._meta] = qs
+ title = _("{total} search results for '{query}'").format(total=total, query=query)
+ context = {
+ 'title': mark_safe(title),
+ 'total': total,
+ 'columns': min(int(total/17), 3),
+ 'query': query,
+ 'results': results,
+ 'search_autofocus': True,
+ }
+ return render(request, 'admin/orchestra/search.html', context)
+
+
+admin.site.register_url(r'^search/$', search, 'orchestra_search_view')
diff --git a/orchestra/contrib/accounts/admin.py b/orchestra/contrib/accounts/admin.py
index 01de11a2..db58194b 100644
--- a/orchestra/contrib/accounts/admin.py
+++ b/orchestra/contrib/accounts/admin.py
@@ -8,6 +8,7 @@ from django.conf.urls import url
from django.contrib import admin, messages
from django.contrib.admin.utils import unquote
from django.contrib.auth import admin as auth
+from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.templatetags.static import static
from django.utils.safestring import mark_safe
@@ -152,6 +153,14 @@ class AccountListAdmin(AccountAdmin):
if hasattr(response, 'context_data'):
# user has submitted a change list change, we redirect directly to the add view
# if there is only one result
+ query = request.GET.get('q', '')
+ if query:
+ try:
+ account = Account.objects.get(username=query)
+ except Account.DoesNotExist:
+ pass
+ else:
+ return HttpResponseRedirect('../?account=%i' % account.pk)
queryset = response.context_data['cl'].queryset
if len(queryset) == 1:
return HttpResponseRedirect('../?account=%i' % queryset[0].pk)
diff --git a/orchestra/templates/admin/orchestra/menu.html b/orchestra/templates/admin/orchestra/menu.html
index 48901324..9adee58f 100644
--- a/orchestra/templates/admin/orchestra/menu.html
+++ b/orchestra/templates/admin/orchestra/menu.html
@@ -1,5 +1,6 @@
{% load i18n admin_tools_menu_tags %}
{% if menu.children %}
+