|
1 # |
|
2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net> |
|
3 # All Rights Reserved. |
|
4 # |
|
5 # This software is subject to the provisions of the Zope Public License, |
|
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. |
|
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED |
|
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS |
|
10 # FOR A PARTICULAR PURPOSE. |
|
11 # |
|
12 |
|
13 __docformat__ = 'restructuredtext' |
|
14 |
|
15 |
|
16 # import standard library |
|
17 |
|
18 # import interfaces |
|
19 from hypatia.interfaces import ICatalog |
|
20 from pyams_content.profile.interfaces import IAdminProfile |
|
21 from pyams_content.shared.common.interfaces import ISharedTool |
|
22 from pyams_content.shared.common.interfaces.zmi import ISharedToolDashboardTable |
|
23 from pyams_pagelet.interfaces import PageletCreatedEvent |
|
24 from pyams_sequence.interfaces import ISequentialIntIds |
|
25 from pyams_skin.interfaces import IPageHeader, IContentSearch |
|
26 from pyams_skin.layer import IPyAMSLayer |
|
27 from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION |
|
28 from pyams_workflow.interfaces import IWorkflowVersions, IWorkflow |
|
29 from pyams_zmi.interfaces import IAdminView |
|
30 from z3c.table.interfaces import IValues |
|
31 from zope.dublincore.interfaces import IZopeDublinCore |
|
32 |
|
33 # import packages |
|
34 from hypatia.catalog import CatalogQuery |
|
35 from hypatia.query import Eq, Contains, Ge, Le |
|
36 from pyams_content.workflow import STATES_VOCABULARY |
|
37 from pyams_catalog.query import CatalogResultSet |
|
38 from pyams_form.search import SearchView, SearchForm, SearchResultsView, ISearchFields |
|
39 from pyams_pagelet.pagelet import pagelet_config |
|
40 from pyams_security.schema import Principal |
|
41 from pyams_skin.page import DefaultPageHeaderAdapter |
|
42 from pyams_skin.table import BaseTable |
|
43 from pyams_template.template import template_config |
|
44 from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter |
|
45 from pyams_utils.list import unique |
|
46 from pyams_utils.registry import get_utility |
|
47 from pyams_zmi.view import AdminView |
|
48 from pyramid.response import Response |
|
49 from pyramid.view import view_config |
|
50 from z3c.form import field |
|
51 from zope.interface import implementer |
|
52 from zope.schema import Date, Choice |
|
53 |
|
54 from pyams_content import _ |
|
55 |
|
56 |
|
57 # |
|
58 # Quick search adapters |
|
59 # |
|
60 |
|
61 @view_config(name='quick-search.html', context=ISharedTool, request_type=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) |
|
62 def shared_tool_quick_search_view(request): |
|
63 """Shared tool quick search view""" |
|
64 results = SharedToolQuickSearchResults(request.context, request) |
|
65 results.update() |
|
66 return Response(results.render()) |
|
67 |
|
68 |
|
69 @implementer(ISharedToolDashboardTable) |
|
70 class SharedToolQuickSearchResults(BaseTable): |
|
71 """Shared tool quick search results table""" |
|
72 |
|
73 title = _("Quick search results") |
|
74 |
|
75 sortOn = None |
|
76 |
|
77 @property |
|
78 def data_attributes(self): |
|
79 attributes = super(SharedToolQuickSearchResults, self).data_attributes |
|
80 attributes['table'] = {'data-ams-datatable-sorting': '[]', |
|
81 'data-ams-datatable-display-length': |
|
82 IAdminProfile(self.request.principal).table_page_length} |
|
83 return attributes |
|
84 |
|
85 |
|
86 @adapter_config(context=(ISharedTool, IPyAMSLayer, SharedToolQuickSearchResults), provides=IValues) |
|
87 class SharedToolQuickSearchValues(ContextRequestViewAdapter): |
|
88 """Shared tool quick search results view values adapter""" |
|
89 |
|
90 @property |
|
91 def values(self): |
|
92 catalog = get_utility(ICatalog) |
|
93 params = Eq(catalog['content_type'], self.context.shared_content_type) |
|
94 query = self.request.params.get('query') |
|
95 if query: |
|
96 sequence = get_utility(ISequentialIntIds) |
|
97 if query.startswith('+'): |
|
98 params &= Eq(catalog['oid'], sequence.get_full_oid(query)) |
|
99 else: |
|
100 query_params = Eq(catalog['oid'], sequence.get_full_oid(query)) |
|
101 index = catalog['title:' + self.request.registry.settings.get('pyramid.default_locale_name', 'en')] |
|
102 if index.check_query(query): |
|
103 query_params |= Contains(index, ' and '.join((w+'*' for w in query.split()))) |
|
104 params &= query_params |
|
105 return unique(map(lambda x: IWorkflowVersions(x).get_last_versions()[0], |
|
106 CatalogResultSet(CatalogQuery(catalog).query(params, |
|
107 sort_index='modified_date', |
|
108 reverse=True)))) |
|
109 |
|
110 |
|
111 # |
|
112 # Advanced search adapters |
|
113 # |
|
114 |
|
115 class ISharedToolAdvancedSearchFields(ISearchFields): |
|
116 """Shared tool advanced search fields""" |
|
117 |
|
118 owner = Principal(title=_("Owner"), |
|
119 required=False) |
|
120 |
|
121 status = Choice(title=_("Status"), |
|
122 vocabulary=STATES_VOCABULARY, |
|
123 required=False) |
|
124 |
|
125 created_after = Date(title=_("Created after..."), |
|
126 required=False) |
|
127 |
|
128 created_before = Date(title=_("Created before..."), |
|
129 required=False) |
|
130 |
|
131 modified_after = Date(title=_("Modified after..."), |
|
132 required=False) |
|
133 |
|
134 modified_before = Date(title=_("Modified before..."), |
|
135 required=False) |
|
136 |
|
137 |
|
138 @template_config(template='templates/advanced-search.pt', layer=IPyAMSLayer) |
|
139 @implementer(IAdminView) |
|
140 class SharedToolAdvancedSearchForm(SearchForm): |
|
141 """Shared tool advanced search form""" |
|
142 |
|
143 legend = _("Advanced search") |
|
144 |
|
145 ajax_handler = 'advanced-search-results.html' |
|
146 |
|
147 def __init__(self, context, request): |
|
148 super(SharedToolAdvancedSearchForm, self).__init__(context, request) |
|
149 request.registry.notify(PageletCreatedEvent(self)) |
|
150 |
|
151 @property |
|
152 def fields(self): |
|
153 workflow = IWorkflow(self.context) |
|
154 fields = field.Fields(ISharedToolAdvancedSearchFields) |
|
155 fields['status'].vocabulary = workflow.states |
|
156 return fields |
|
157 |
|
158 |
|
159 @adapter_config(context=(ISharedTool, IPyAMSLayer, SharedToolAdvancedSearchForm), provides=IContentSearch) |
|
160 class SharedToolAdvancedSearchFormSearchAdapter(ContextRequestViewAdapter): |
|
161 """Shared tool adavanced search form search adapter""" |
|
162 |
|
163 def get_search_results(self, data): |
|
164 catalog = get_utility(ICatalog) |
|
165 params = Eq(catalog['content_type'], self.context.shared_content_type) |
|
166 query = data.get('query') |
|
167 if query: |
|
168 sequence = get_utility(ISequentialIntIds) |
|
169 if query.startswith('+'): |
|
170 params &= Eq(catalog['oid'], sequence.get_full_oid(query)) |
|
171 else: |
|
172 query_params = Eq(catalog['oid'], sequence.get_full_oid(query)) |
|
173 index = catalog['title:' + self.request.registry.settings.get('pyramid.default_locale_name', 'en')] |
|
174 if index.check_query(query): |
|
175 query_params |= Contains(index, ' and '.join((w+'*' for w in query.split()))) |
|
176 params &= query_params |
|
177 if data.get('owner'): |
|
178 params &= Eq(catalog['owner'], data['owner']) |
|
179 if data.get('status'): |
|
180 params &= Eq(catalog['workflow_state'], data['status']) |
|
181 if data.get('created_after'): |
|
182 params &= Ge(catalog['created_date'], data['created_after']) |
|
183 if data.get('created_before'): |
|
184 params &= Le(catalog['created_date'], data['created_before']) |
|
185 if data.get('modified_after'): |
|
186 params &= Ge(catalog['modified_date'], data['modified_after']) |
|
187 if data.get('modified_before'): |
|
188 params &= Le(catalog['modified_date'], data['modified_before']) |
|
189 if data.get('status'): |
|
190 return unique(map(lambda x: sorted(IWorkflowVersions(x).get_versions(data['status']), |
|
191 key=lambda y: IZopeDublinCore(y).modified)[0], |
|
192 CatalogResultSet(CatalogQuery(catalog).query(params, |
|
193 sort_index='modified_date', |
|
194 reverse=True)))) |
|
195 else: |
|
196 return unique(map(lambda x: IWorkflowVersions(x).get_last_versions()[0], |
|
197 CatalogResultSet(CatalogQuery(catalog).query(params, |
|
198 sort_index='modified_date', |
|
199 reverse=True)))) |
|
200 |
|
201 |
|
202 @pagelet_config(name='advanced-search.html', context=ISharedTool, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) |
|
203 class SharedToolAdvancedSearchView(AdminView, SearchView): |
|
204 """Shared tool advanced search view""" |
|
205 |
|
206 search_form_factory = SharedToolAdvancedSearchForm |
|
207 |
|
208 |
|
209 @adapter_config(context=(ISharedTool, IPyAMSLayer, SharedToolAdvancedSearchView), provides=IPageHeader) |
|
210 class SharedToolAdvancedSearchHeaderAdapter(DefaultPageHeaderAdapter): |
|
211 """Shared tool advanced search header adapter""" |
|
212 |
|
213 back_url = '#dashboard.html' |
|
214 back_target = None |
|
215 |
|
216 icon_class = 'fa fa-fw fa-search' |
|
217 |
|
218 |
|
219 @view_config(name='advanced-search-results.html', context=ISharedTool, request_type=IPyAMSLayer, |
|
220 permission=VIEW_SYSTEM_PERMISSION) |
|
221 @implementer(ISharedToolDashboardTable) |
|
222 class SharedToolAdvancedSearchResultsView(AdminView, SearchResultsView): |
|
223 """Shared tool advanced search results view""" |
|
224 |
|
225 title = _("Advanced search results") |
|
226 search_form_factory = SharedToolAdvancedSearchForm |
|
227 |
|
228 sortOn = None |
|
229 |
|
230 def __init__(self, context, request): |
|
231 super(SharedToolAdvancedSearchResultsView, self).__init__(context, request) |
|
232 request.registry.notify(PageletCreatedEvent(self)) |
|
233 |
|
234 @property |
|
235 def data_attributes(self): |
|
236 attributes = super(SharedToolAdvancedSearchResultsView, self).data_attributes |
|
237 attributes['table'] = {'data-ams-datatable-sorting': '[]', |
|
238 'data-ams-datatable-display-length': |
|
239 IAdminProfile(self.request.principal).table_page_length} |
|
240 return attributes |
|
241 |
|
242 |
|
243 @adapter_config(context=(ISharedTool, IPyAMSLayer, SharedToolAdvancedSearchResultsView), provides=IValues) |
|
244 class SearchResultsViewValuesAdapter(ContextRequestViewAdapter): |
|
245 """Search results view values adapter""" |
|
246 |
|
247 @property |
|
248 def values(self): |
|
249 form = self.view.search_form_factory(self.context, self.request) |
|
250 return form.get_search_results() |