src/pyams_content/root/zmi/search.py
changeset 304 14b2ae98f78c
parent 0 7c0001cacf8e
child 334 6b2f75e60076
--- a/src/pyams_content/root/zmi/search.py	Mon Dec 04 15:36:40 2017 +0100
+++ b/src/pyams_content/root/zmi/search.py	Fri Dec 08 10:41:32 2017 +0100
@@ -16,5 +16,263 @@
 # import standard library
 
 # import interfaces
+from hypatia.interfaces import ICatalog
+from pyams_content.profile.interfaces import IAdminProfile
+from pyams_content.root import ISiteRoot
+from pyams_content.shared.common.interfaces.zmi import ISiteRootDashboardTable
+from pyams_content.zmi.interfaces import IAllContentsMenu
+from pyams_form.search import ISearchFields, SearchForm, SearchView, SearchResultsView
+from pyams_i18n.interfaces import INegotiator
+from pyams_sequence.interfaces import ISequentialIntIds
+from pyams_skin.interfaces import IInnerPage, IContentSearch, IPageHeader
+from pyams_skin.layer import IPyAMSLayer
+from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION
+from pyams_workflow.interfaces import IWorkflowVersions
+from pyams_zmi.layer import IAdminLayer
+from z3c.table.interfaces import IValues
+from zope.intid import IIntIds
 
 # import packages
+from hypatia.catalog import CatalogQuery
+from hypatia.query import Eq, Any, Contains, Ge, Le
+from pyams_catalog.query import CatalogResultSet
+from pyams_content.shared.common import CONTENT_TYPES
+from pyams_pagelet.interfaces import PageletCreatedEvent
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_security.schema import Principal
+from pyams_skin.page import DefaultPageHeaderAdapter
+from pyams_skin.skin import apply_skin
+from pyams_skin.table import BaseTable
+from pyams_skin.viewlet.menu import MenuItem
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter
+from pyams_utils.list import unique
+from pyams_utils.registry import get_utility
+from pyams_utils.url import absolute_url
+from pyams_viewlet.viewlet import viewlet_config
+from pyams_zmi.view import AdminView
+from pyramid.view import view_config
+from z3c.form import field
+from zope.interface import implementer
+from zope.schema import Datetime, Choice, List
+
+from pyams_content import _
+
+
+#
+# Quick search adapters
+#
+
+@view_config(name='quick-search.html', context=ISiteRoot, request_type=IPyAMSLayer,
+             permission=VIEW_SYSTEM_PERMISSION, renderer='json', xhr=True)
+def site_root_quick_search_view(request):
+    """Site root quick search view"""
+    results = SiteRootQuickSearchResults(request.context, request)
+    if len(results.values) == 1:
+        result = results.values[0]
+        return {'status': 'redirect',
+                'location': absolute_url(result, request, 'admin')}
+    else:
+        results.update()
+        return {'status': 'info',
+                'content': {'html': results.render()}}
+
+
+@implementer(ISiteRootDashboardTable)
+class SiteRootQuickSearchResults(BaseTable):
+    """Site root quick search results table"""
+
+    title = _("Quick search results")
+
+    sortOn = None
+
+    @property
+    def data_attributes(self):
+        attributes = super(SiteRootQuickSearchResults, self).data_attributes
+        attributes['table'] = {'data-ams-datatable-sorting': '[]',
+                               'data-ams-datatable-display-length':
+                                   IAdminProfile(self.request.principal).table_page_length}
+        return attributes
+
+
+@adapter_config(context=(ISiteRoot, IPyAMSLayer, SiteRootQuickSearchResults), provides=IValues)
+class SiteRootQuickSearchValues(ContextRequestViewAdapter):
+    """Site root quick search results view values adapter"""
+
+    @property
+    def values(self):
+        intids = get_utility(IIntIds)
+        catalog = get_utility(ICatalog)
+        params = Eq(catalog['parents'], intids.register(self.context)) & \
+                 Any(catalog['content_type'], CONTENT_TYPES.keys())
+        query = self.request.params.get('query')
+        if query:
+            sequence = get_utility(ISequentialIntIds)
+            if query.startswith('+'):
+                params &= Eq(catalog['oid'], sequence.get_full_oid(query))
+            else:
+                query_params = Eq(catalog['oid'], sequence.get_full_oid(query))
+                negotiator = get_utility(INegotiator)
+                for lang in {self.request.registry.settings.get('pyramid.default_locale_name', 'en'),
+                             self.request.locale_name,
+                             negotiator.server_language} | negotiator.offered_languages:
+                    index_name = 'title:{0}'.format(lang)
+                    if index_name in catalog:
+                        index = catalog[index_name]
+                        if index.check_query(query):
+                            query_params |= Contains(index, ' and '.join((w+'*' for w in query.split())))
+                params &= query_params
+        return unique(map(lambda x: IWorkflowVersions(x).get_last_versions()[0],
+                          CatalogResultSet(CatalogQuery(catalog).query(params,
+                                                                       sort_index='modified_date',
+                                                                       reverse=True))))
+
+
+#
+# Advanced search adapters
+#
+
+@viewlet_config(name='advanced-search.menu', context=ISiteRoot, layer=IAdminLayer,
+                manager=IAllContentsMenu, permission=VIEW_SYSTEM_PERMISSION, weight=90)
+class SiteRootAdvancedSearchMenu(MenuItem):
+    """Site root advanced search menu"""
+
+    label = _("Advanced search")
+    icon_class = None
+    url = '#advanced-search.html'
+
+
+class ISiteRootAdvancedSearchFields(ISearchFields):
+    """Site root advanced search fields"""
+
+    content_type = List(title=_("Content types"),
+                        value_type=Choice(vocabulary='PyAMS content types'),
+                        required=False)
+
+    owner = Principal(title=_("Owner"),
+                      required=False)
+
+    created_after = Datetime(title=_("Created after..."),
+                             required=False)
+
+    created_before = Datetime(title=_("Created before..."),
+                              required=False)
+
+    modified_after = Datetime(title=_("Modified after..."),
+                              required=False)
+
+    modified_before = Datetime(title=_("Modified before..."),
+                               required=False)
+
+
+@template_config(template='templates/advanced-search.pt', layer=IPyAMSLayer)
+@implementer(IInnerPage)
+class SiteRootAdvancedSearchForm(SearchForm):
+    """Site root advanced search form"""
+
+    legend = _("Advanced search")
+
+    def __init__(self, context, request):
+        super(SiteRootAdvancedSearchForm, self).__init__(context, request)
+        request.registry.notify(PageletCreatedEvent(self))
+        apply_skin(self.request, 'PyAMS admin skin')
+
+    fields = field.Fields(ISiteRootAdvancedSearchFields)
+    ajax_handler = 'advanced-search-results.html'
+
+
+@adapter_config(context=(ISiteRoot, IPyAMSLayer, SiteRootAdvancedSearchForm), provides=IContentSearch)
+class SiteRootAdvancedSearchFormSearchAdapter(ContextRequestViewAdapter):
+    """Site root advanced search form search adapter"""
+
+    def get_search_results(self, data):
+        intids = get_utility(IIntIds)
+        catalog = get_utility(ICatalog)
+        params = Eq(catalog['parents'], intids.register(self.context))
+        if data.get('content_type'):
+            params &= Any(catalog['content_type'], data['content_type'])
+        else:
+            params &= Any(catalog['content_type'], CONTENT_TYPES.keys())
+        query = data.get('query')
+        if query:
+            sequence = get_utility(ISequentialIntIds)
+            if query.startswith('+'):
+                params &= Eq(catalog['oid'], sequence.get_full_oid(query))
+            else:
+                query_params = Eq(catalog['oid'], sequence.get_full_oid(query))
+                negotiator = get_utility(INegotiator)
+                for lang in {self.request.registry.settings.get('pyramid.default_locale_name', 'en'),
+                             self.request.locale_name,
+                             negotiator.server_language} | negotiator.offered_languages:
+                    index_name = 'title:{0}'.format(lang)
+                    if index_name in catalog:
+                        index = catalog[index_name]
+                        if index.check_query(query):
+                            query_params |= Contains(index, ' and '.join((w+'*' for w in query.split())))
+                params &= query_params
+        if data.get('owner'):
+            params &= Eq(catalog['role:owner'], data['owner'])
+        if data.get('created_after'):
+            params &= Ge(catalog['created_date'], data['created_after'])
+        if data.get('created_before'):
+            params &= Le(catalog['created_date'], data['created_before'])
+        if data.get('modified_after'):
+            params &= Ge(catalog['modified_date'], data['modified_after'])
+        if data.get('modified_before'):
+            params &= Le(catalog['modified_date'], data['modified_before'])
+        return unique(map(lambda x: IWorkflowVersions(x).get_last_versions()[0],
+                          CatalogResultSet(CatalogQuery(catalog).query(params,
+                                                                       sort_index='modified_date',
+                                                                       reverse=True))))
+
+
+@pagelet_config(name='advanced-search.html', context=ISiteRoot, layer=IPyAMSLayer,
+                permission=VIEW_SYSTEM_PERMISSION)
+class SiteRootAdvancedSearchView(SearchView):
+    """Site root advanced search view"""
+
+    search_form_factory = SiteRootAdvancedSearchForm
+
+
+@adapter_config(context=(ISiteRoot, IPyAMSLayer, SiteRootAdvancedSearchView), provides=IPageHeader)
+class SiteRootAdvancedSearchHeaderAdapter(DefaultPageHeaderAdapter):
+    """Site root advanced search header adapter"""
+
+    back_url = '#dashboard.html'
+    back_target = None
+
+    icon_class = 'fa fa-fw fa-search'
+
+
+@view_config(name='advanced-search-results.html', context=ISiteRoot, request_type=IPyAMSLayer,
+             permission=VIEW_SYSTEM_PERMISSION)
+@implementer(ISiteRootDashboardTable)
+class SiteRootAdvancedSearchResultsView(AdminView, SearchResultsView):
+    """Site root advanced search results view"""
+
+    title = _("Advanced search results")
+    search_form_factory = SiteRootAdvancedSearchForm
+
+    sortOn = None
+
+    def __init__(self, context, request):
+        super(SiteRootAdvancedSearchResultsView, self).__init__(context, request)
+        request.registry.notify(PageletCreatedEvent(self))
+
+    @property
+    def data_attributes(self):
+        attributes = super(SiteRootAdvancedSearchResultsView, self).data_attributes
+        attributes['table'] = {'data-ams-datatable-sorting': '[]',
+                               'data-ams-datatable-display-length':
+                                   IAdminProfile(self.request.principal).table_page_length}
+        return attributes
+
+
+@adapter_config(context=(ISiteRoot, IPyAMSLayer, SiteRootAdvancedSearchResultsView), provides=IValues)
+class SearchResultsViewValuesAdapter(ContextRequestViewAdapter):
+    """Search results view values adapter"""
+
+    @property
+    def values(self):
+        form = self.view.search_form_factory(self.context, self.request)
+        return form.get_search_results() or ()