Permalink
Browse files

Fixes bug 890946 - Added a page to execute custom queries. r=peterbe

  • Loading branch information...
1 parent badd0a1 commit 9beda86a275d94afe85d2a2973c4d700d69080a5 @adngdb adngdb committed Aug 19, 2013
Showing with 764 additions and 288 deletions.
  1. +6 −1 socorro/external/elasticsearch/query.py
  2. +4 −1 socorro/external/elasticsearch/supersearch.py
  3. +3 −1 socorro/unittest/external/elasticsearch/test_query.py
  4. +6 −3 socorro/unittest/external/elasticsearch/test_supersearch.py
  5. BIN webapp-django/crashstats/base/static/img/3rdparty/silk/wrench.png
  6. +1 −0 webapp-django/crashstats/crashstats/management/__init__.py
  7. +4 −0 webapp-django/crashstats/settings/base.py
  8. +13 −0 webapp-django/crashstats/supersearch/forms.py
  9. +26 −1 webapp-django/crashstats/supersearch/models.py
  10. +30 −0 webapp-django/crashstats/supersearch/static/supersearch/css/search.less
  11. BIN webapp-django/crashstats/supersearch/static/supersearch/img/select2/select2.png
  12. +1 −0 webapp-django/crashstats/supersearch/static/supersearch/js/lib/ace/ace.js
  13. +1 −0 webapp-django/crashstats/supersearch/static/supersearch/js/lib/ace/mode-json.js
  14. +1 −0 webapp-django/crashstats/supersearch/static/supersearch/js/lib/ace/theme-monokai.js
  15. +1 −0 webapp-django/crashstats/supersearch/static/supersearch/js/lib/ace/worker-json.js
  16. +8 −4 webapp-django/crashstats/supersearch/static/supersearch/js/lib/dynamic_form.js
  17. +0 −22 webapp-django/crashstats/supersearch/static/supersearch/js/lib/select2.js
  18. +18 −0 webapp-django/crashstats/supersearch/static/supersearch/js/lib/select2/LICENSE
  19. BIN webapp-django/crashstats/supersearch/static/supersearch/{img → js/lib}/select2/select2-spinner.gif
  20. +113 −150 webapp-django/crashstats/supersearch/static/supersearch/{css → js/lib}/select2/select2.css
  21. +22 −0 webapp-django/crashstats/supersearch/static/supersearch/js/lib/select2/select2.js
  22. BIN webapp-django/crashstats/supersearch/static/supersearch/js/lib/select2/select2.png
  23. BIN webapp-django/crashstats/supersearch/static/supersearch/js/lib/select2/select2x2.png
  24. +19 −5 webapp-django/crashstats/supersearch/static/supersearch/js/socorro/search.js
  25. +123 −0 webapp-django/crashstats/supersearch/static/supersearch/js/socorro/search_custom.js
  26. +18 −3 webapp-django/crashstats/supersearch/templates/supersearch/search.html
  27. +65 −0 webapp-django/crashstats/supersearch/templates/supersearch/search_custom.html
  28. +149 −53 webapp-django/crashstats/supersearch/tests/test_views.py
  29. +6 −0 webapp-django/crashstats/supersearch/urls.py
  30. +126 −44 webapp-django/crashstats/supersearch/views.py
@@ -5,6 +5,7 @@
import datetime
import json
import pyelasticsearch
+import re
from pyelasticsearch.exceptions import (
ElasticHttpError,
ElasticHttpNotFoundError,
@@ -18,6 +19,7 @@
ResourceNotFound,
)
from socorro.external.elasticsearch.base import ElasticSearchBase
+from socorro.external.elasticsearch.supersearch import BAD_INDEX_REGEX
from socorro.lib import external_common
from socorro.lib.datetimeutil import utc_now
@@ -74,7 +76,10 @@ def get(self, **kwargs):
**search_args
)
except ElasticHttpNotFoundError, e:
- raise ResourceNotFound(e)
+ missing_index = re.findall(BAD_INDEX_REGEX, e.error)[0]
+ raise ResourceNotFound(
+ "elasticsearch index '%s' does not exist" % missing_index
+ )
except (InvalidJsonResponseError, ElasticHttpError), e:
raise DatabaseError(e)
@@ -377,7 +377,10 @@ def get(self, **kwargs):
if params['_return_query'][0].value[0]:
# Return only the JSON query that would be sent to elasticsearch.
- return search._build_query()
+ return {
+ 'query': search._build_query(),
+ 'indices': indexes,
+ }
# We call elasticsearch with a computed list of indices, based on
# the date range. However, if that list contains indices that do not
@@ -141,7 +141,9 @@ def test_get_with_errors(self, mocked_es):
mocked_connection = mock.Mock()
mocked_es.ElasticSearch.return_value = mocked_connection
- mocked_connection.search.side_effect = ElasticHttpNotFoundError('aaa')
+ mocked_connection.search.side_effect = ElasticHttpNotFoundError(
+ 404, '[[socorro_201801] missing]'
+ )
assert_raises(
ResourceNotFound,
self.api.get,
@@ -890,6 +890,9 @@ def test_return_query_mode(self):
'_return_query': 'true'
}
res = self.api.get(**kwargs)
- ok_('filter' in res)
- ok_('facets' in res)
- ok_('size' in res)
+ ok_('query' in res)
+ ok_('indices' in res)
+ query = res['query']
+ ok_('filter' in query)
+ ok_('facets' in query)
+ ok_('size' in query)
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -16,6 +16,7 @@
'view_rawdump': 'View Raw Dumps',
'view_exploitability': 'View Exploitability Results',
'view_flash_exploitability': 'View Flash Exploitability Results',
+ 'run_custom_queries': 'Run Custom Queries in Super Search',
'run_long_queries': 'Run Long Queries',
'upload_symbols': 'Upload Symbols Files',
}
@@ -273,6 +273,10 @@
# Leave empty to use the default
SEARCH_MIDDLEWARE_IMPL = None
+# The index schema used in our elasticsearch databases, used in the
+# Super Search Custom Query page.
+ELASTICSEARCH_INDEX_SCHEMA = 'socorro%Y%W'
+
# Valid type for correlations reports
CORRELATION_REPORT_TYPES = (
'core-counts',
@@ -1,3 +1,5 @@
+import json
+
from django import forms
from django.conf import settings
@@ -184,3 +186,14 @@ def get_fields_list(self):
}
return fields_list
+
+
+class QueryForm(forms.Form):
+ query = forms.CharField()
+ indices = form_fields.MultipleValueField(required=False)
+
+ def clean_query(self):
+ try:
+ return json.loads(self.cleaned_data['query'])
+ except ValueError as x:
+ raise forms.ValidationError(x)
@@ -1,3 +1,5 @@
+import json
+
from crashstats.crashstats import models
from . import forms
@@ -12,7 +14,30 @@ class SuperSearch(models.SocorroMiddleware):
possible_params = tuple(
x for x in forms.SearchForm([], [], [], True, True).fields
) + (
+ '_facets',
'_results_offset',
'_results_number',
- '_facets',
+ '_return_query',
)
+
+
+class Query(models.SocorroMiddleware):
+ # No API_WHITELIST because this can't be accessed through the public API.
+
+ URL_PREFIX = '/query/'
+
+ required_params = (
+ 'query',
+ )
+
+ possible_params = (
+ 'indices',
+ )
+
+ def get(self, **kwargs):
+ params = self.kwargs_to_params(kwargs)
+ payload = {
+ 'query': json.dumps(params['query']),
+ 'indices': params.get('indices'),
+ }
+ return self.post(self.URL_PREFIX, payload)
@@ -20,6 +20,12 @@
.new-line:before {
content: url(../../img/3rdparty/silk/application_form_add.png);
}
+ .customize {
+ clear: both;
+ }
+ .customize:before {
+ content: url(../../img/3rdparty/silk/wrench.png);
+ }
fieldset {
padding: 10px 0;
@@ -79,6 +85,16 @@
display: inline;
width: 500px;
}
+
+ input[name=search_indices] {
+ display: inline;
+ width: 80%;
+ }
+ }
+
+ textarea {
+ height: 300px;
+ width: 600px;
}
}
@@ -103,3 +119,17 @@
margin: auto;
width: 220px;
}
+
+/* Custom Query styles */
+#editor {
+ border: 1px solid lightgray;
+ height: 400px;
+ margin: 0;
+ width: 80%;
+}
+.json-results {
+ font-family: "Monaco", "Menlo", "Ubuntu Mono", "Consolas", "source-code-pro", monospace;
+ font-size: 12px;
+ height: 500px;
+ width: 100%;
+}

Large diffs are not rendered by default.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -361,7 +361,8 @@
this.line.append(this.fieldInput);
this.fieldInput.select2({
- placeholder: 'Choose a field'
+ placeholder: 'Choose a field',
+ width: 'element'
});
this.fieldInput.on('change', this.createOperatorInput.bind(this));
@@ -395,14 +396,16 @@
this.line.append(this.operatorInput);
- this.operatorInput.select2();
+ this.operatorInput.select2({
+ width: 'element'
+ });
this.operatorInput.on('change', function (e) {
// We should create the value input only if there was no value
// yet or the previous operator was a "no-value" one, and
// the new operator accepts values.
if (
OPERATORS_NO_VALUE.indexOf(e.added.id) === -1 && (
- !e.removed.text ||
+ !e.removed ||
OPERATORS_NO_VALUE.indexOf(e.removed.id) > -1
)
) {
@@ -458,7 +461,8 @@
this.line.append(this.valueInput);
var selectParams = {
- 'separator': VALUES_SEPARATOR
+ 'separator': VALUES_SEPARATOR,
+ 'width': 'element'
};
if (field.extendable !== false) {
selectParams.tags = values;
Oops, something went wrong.

0 comments on commit 9beda86

Please sign in to comment.