| #!/usr/bin/env python |
| # |
| # Copyright 2007 Google Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| """Handlers that display full-text search indexes and documents.""" |
| |
| import urllib |
| |
| from google.appengine.api import search |
| from google.appengine.tools.devappserver2.admin import admin_request_handler |
| |
| |
| class BaseSearchHandler(admin_request_handler.AdminRequestHandler): |
| _MAX_RESULTS_PER_PAGE = 20 |
| |
| def _handle_paging(self, start, has_more, values): |
| if has_more: |
| values['next_url'] = self._construct_url( |
| add={'start': start + self._MAX_RESULTS_PER_PAGE}) |
| values['paging'] = True |
| if start > 0: |
| values['previous_url'] = self._construct_url( |
| add={'start': max(0, start - self._MAX_RESULTS_PER_PAGE)}) |
| values['paging'] = True |
| |
| |
| class SearchIndexesListHandler(BaseSearchHandler): |
| |
| def get(self): |
| start = self.request.get_range('start', min_value=0, default=0) |
| namespace = self.request.get('namespace', default_value=None) |
| resp = search.get_indexes(offset=start, |
| limit=self._MAX_RESULTS_PER_PAGE + 1, |
| namespace=namespace or '') |
| has_more = len(resp.results) > self._MAX_RESULTS_PER_PAGE |
| indexes = resp.results[:self._MAX_RESULTS_PER_PAGE] |
| |
| values = { |
| 'namespace': namespace or '', |
| 'has_namespace': namespace is not None, |
| 'indexes': indexes} |
| self._handle_paging(start, has_more, values) |
| |
| self.response.write(self.render('search.html', values)) |
| |
| |
| class SearchIndexHandler(BaseSearchHandler): |
| |
| def _process_search_response(self, response): |
| |
| documents = [] |
| field_names = set() |
| |
| # Collect field names. |
| for result in response.results: |
| fields = dict((field.name, field.value) for field in result.fields) |
| field_names.update(fields) |
| documents.append((result.doc_id, fields)) |
| |
| field_names = sorted(field_names) |
| template_documents = [] |
| |
| for doc_id, fields in documents: |
| doc_fields = [fields.get(field_name, '') for field_name in field_names] |
| template_documents.append({'doc_id': doc_id, 'fields': doc_fields}) |
| |
| return {'documents': template_documents, 'field_names': field_names} |
| |
| def get(self): |
| index_name = self.request.get('index') |
| if not index_name: |
| self.redirect('/search') |
| return |
| start = self.request.get_range('start', min_value=0, default=0) |
| query = self.request.get('query') |
| namespace = self.request.get('namespace') |
| index = search.Index(name=index_name, namespace=namespace) |
| resp = index.search(query=search.Query( |
| query_string=query, |
| options=search.QueryOptions(offset=start, |
| limit=self._MAX_RESULTS_PER_PAGE))) |
| has_more = resp.number_found > start + self._MAX_RESULTS_PER_PAGE |
| |
| values = { |
| 'namespace': namespace, |
| 'index': index_name, |
| 'start': start, |
| 'query': query, |
| 'values': self._process_search_response(resp), |
| } |
| self._handle_paging(start, has_more, values) |
| self.response.write(self.render('search_index.html', values)) |
| |
| def post(self): |
| index_name = self.request.get('index') |
| namespace = self.request.get('namespace') |
| start = self.request.get_range('start', min_value=0, default=0) |
| |
| index = 0 |
| num_docs = int(self.request.get('numdocs')) |
| docs = self.request.params.getall('doc_id') |
| if len(docs) == num_docs: |
| start = max(0, start - self._MAX_RESULTS_PER_PAGE) |
| |
| index = search.Index(name=index_name, namespace=namespace) |
| index.delete(docs) |
| self.redirect('/search/index?%s' % urllib.urlencode( |
| {'namespace': namespace, |
| 'index': index_name, |
| 'start': start})) |
| |
| |
| class SearchDocumentHandler(BaseSearchHandler): |
| |
| def get(self): |
| index_name = self.request.get('index') |
| doc_id = self.request.get('id') |
| namespace = self.request.get('namespace') |
| doc = None |
| index = search.Index(name=index_name, namespace=namespace) |
| resp = index.get_range(start_id=doc_id, limit=1) |
| if resp.results and resp.results[0].doc_id == doc_id: |
| doc = resp.results[0] |
| |
| values = { |
| 'namespace': namespace, |
| 'index': index_name, |
| 'doc_id': doc_id, |
| 'doc': doc, |
| } |
| self.response.write(self.render('search_document.html', values)) |