Attachment 'fullsearch_new.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 MoinMoin - fullsearch action
4
5 This is the backend of the search form. Search pages and print results.
6
7 @copyright: 2001 by Juergen Hermann <jh@web.de>
8 @license: GNU GPL, see COPYING for details.
9
10 Comments about my changes (MarcelHäfner / 24.06.2009):
11 I wanted a search witch finds/displays only wiki pages (primary no attachments)
12 For this I changed this action; so you can now add to our theme / html searchform
13 a hidden paramter like this:
14 <input id="searchmimetype" type="hidden" value="text/wiki" name="mimetype"/>
15
16 for more details, please see on MoinMoin this page: FullSearchMimeTypeSupport
17
18 """
19
20 import re, time
21 from MoinMoin.Page import Page
22 from MoinMoin import wikiutil
23 from MoinMoin.support.parsedatetime.parsedatetime import Calendar
24
25 def checkTitleSearch(request):
26 """ Return 1 for title search, 0 for full text search, -1 for idiot spammer
27 who tries to press all buttons at once.
28
29 When used in FullSearch macro, we have 'titlesearch' parameter with
30 '0' or '1'. In standard search, we have either 'titlesearch' or
31 'fullsearch' with localized string. If both missing, default to
32 True (might happen with Safari) if this isn't an advanced search.
33 """
34 form = request.form
35 if 'titlesearch' in form and 'fullsearch' in form:
36 ret = -1 # spammer / bot
37 else:
38 try:
39 ret = int(form['titlesearch'][0])
40 except ValueError:
41 ret = 1
42 except KeyError:
43 ret = ('fullsearch' not in form and not isAdvancedSearch(request)) and 1 or 0
44 return ret
45
46 def isAdvancedSearch(request):
47 """ Return True if advanced search is requested """
48 try:
49 return int(request.form['advancedsearch'][0])
50 except KeyError:
51 return False
52
53
54 def searchHints(f, hints):
55 """ Return a paragraph showing hints for a search
56
57 @param f: the formatter to use
58 @param hints: list of hints (as strings) to show
59 """
60 return ''.join([
61 f.paragraph(1, attr={'class': 'searchhint'}),
62 # this is illegal formatter usage anyway, so we can directly use a literal
63 "<br>".join(hints),
64 f.paragraph(0),
65 ])
66
67
68 def execute(pagename, request, fieldname='value', titlesearch=0, statistic=0):
69 _ = request.getText
70 titlesearch = checkTitleSearch(request)
71 if titlesearch < 0:
72 request.makeForbidden403()
73 request.surge_protect(kick_him=True) # get rid of spammer
74 return
75
76 advancedsearch = isAdvancedSearch(request)
77
78 # context is relevant only for full search
79 if titlesearch:
80 context = 0
81 elif advancedsearch:
82 context = 180 # XXX: hardcoded context count for advancedsearch
83 else:
84 context = int(request.form.get('context', [0])[0])
85
86 # Get other form parameters
87 needle = request.form.get(fieldname, [''])[0]
88 case = int(request.form.get('case', [0])[0])
89 regex = int(request.form.get('regex', [0])[0]) # no interface currently
90 hitsFrom = int(request.form.get('from', [0])[0])
91 mtime = None
92 msg = ''
93 historysearch = 0
94 mimetype = request.form.get('mimetype', [0]) #moved up; from only used in advanced search
95
96 # if advanced search is enabled we construct our own search query
97 if advancedsearch:
98 and_terms = request.form.get('and_terms', [''])[0].strip()
99 or_terms = request.form.get('or_terms', [''])[0].strip()
100 not_terms = request.form.get('not_terms', [''])[0].strip()
101 #xor_terms = request.form.get('xor_terms', [''])[0].strip()
102 categories = request.form.get('categories', [''])
103 timeframe = request.form.get('time', [''])[0].strip()
104 language = request.form.get('language', [''])
105 excludeunderlay = request.form.get('excludeunderlay', [0])[0]
106 nosystemitems = request.form.get('nosystemitems', [0])[0]
107 historysearch = request.form.get('historysearch', [0])[0]
108
109 mtime = request.form.get('mtime', [''])[0]
110 if mtime:
111 mtime_parsed = None
112
113 # get mtime from known date/time formats
114 for fmt in (request.user.datetime_fmt,
115 request.cfg.datetime_fmt, request.user.date_fmt,
116 request.cfg.date_fmt):
117 try:
118 mtime_parsed = time.strptime(mtime, fmt)
119 except ValueError:
120 continue
121 else:
122 break
123
124 if mtime_parsed:
125 mtime = time.mktime(mtime_parsed)
126 else:
127 # didn't work, let's try parsedatetime
128 cal = Calendar()
129 mtime_parsed, invalid_flag = cal.parse(mtime)
130 # XXX it is unclear if usage of localtime here and in parsedatetime module is correct.
131 # time.localtime is the SERVER's local time and of no relevance to the user (being
132 # somewhere in the world)
133 # mktime is reverse function for localtime, so this maybe fixes it again!?
134 if not invalid_flag and mtime_parsed <= time.localtime():
135 mtime = time.mktime(mtime_parsed)
136 else:
137 mtime_parsed = None # we don't use invalid stuff
138
139 # show info
140 if mtime_parsed:
141 # XXX mtime_msg is not shown in some cases
142 mtime_msg = _("(!) Only pages changed since '''%s''' are being displayed!",
143 wiki=True) % request.user.getFormattedDateTime(mtime)
144 else:
145 mtime_msg = _('/!\\ The modification date you entered was not '
146 'recognized and is therefore not considered for the '
147 'search results!', wiki=True)
148 else:
149 mtime_msg = None
150
151 word_re = re.compile(r'(\"[\w\s]+"|\w+)')
152 needle = ''
153 if categories[0]:
154 needle += 'category:%s ' % ','.join(categories)
155 if language[0]:
156 needle += 'language:%s ' % ','.join(language)
157 if mimetype[0]:
158 needle += 'mimetype:%s ' % ','.join(mimetype)
159 if excludeunderlay:
160 needle += '-domain:underlay '
161 if nosystemitems:
162 needle += '-domain:system '
163 if and_terms:
164 needle += '(%s) ' % and_terms
165 if not_terms:
166 needle += '(%s) ' % ' '.join(['-%s' % t for t in word_re.findall(not_terms)])
167 if or_terms:
168 needle += '(%s) ' % ' or '.join(word_re.findall(or_terms))
169 else:
170 #added for mimetype search over the searchform
171 if mimetype[0]:
172 needle = 'mimetype:%s (%s)' % (','.join(mimetype), needle)
173
174
175 # check for sensible search term
176 stripped = needle.strip()
177 if len(stripped) == 0:
178 request.theme.add_msg(_('Please use a more selective search term instead '
179 'of {{{"%s"}}}', wiki=True) % wikiutil.escape(needle), "error")
180 Page(request, pagename).send_page()
181 return
182 needle = stripped
183
184 # Setup for type of search
185 if titlesearch:
186 title = _('Title Search: "%s"')
187 sort = 'page_name'
188 else:
189 if advancedsearch:
190 title = _('Advanced Search: "%s"')
191 else:
192 title = _('Full Text Search: "%s"')
193 sort = 'weight'
194
195 # search the pages
196 from MoinMoin.search import searchPages, QueryParser, QueryError
197 try:
198 query = QueryParser(case=case, regex=regex,
199 titlesearch=titlesearch).parse_query(needle)
200 except QueryError: # catch errors in the search query
201 request.theme.add_msg(_('Your search query {{{"%s"}}} is invalid. Please refer to '
202 'HelpOnSearching for more information.', wiki=True, percent=True) % wikiutil.escape(needle), "error")
203 Page(request, pagename).send_page()
204 return
205
206 results = searchPages(request, query, sort, mtime, historysearch)
207
208 # directly show a single hit for title searches
209 # this is the "quick jump" functionality if you don't remember
210 # the pagename exactly, but just some parts of it
211 if titlesearch and len(results.hits) == 1:
212 page = results.hits[0]
213 if not page.attachment: # we did not find an attachment
214 page = Page(request, page.page_name)
215 highlight = query.highlight_re()
216 if highlight:
217 querydict = {'highlight': highlight}
218 else:
219 querydict = {}
220 url = page.url(request, querystr=querydict)
221 request.http_redirect(url)
222 return
223 if not results.hits: # no hits?
224 f = request.formatter
225 querydict = wikiutil.parseQueryString(request.query_string)
226 querydict.update({'titlesearch': 0})
227
228 request.theme.add_msg(_('Your search query {{{"%s"}}} didn\'t return any results. '
229 'Please change some terms and refer to HelpOnSearching for '
230 'more information.%s', wiki=True, percent=True) % (wikiutil.escape(needle),
231 titlesearch and ''.join([
232 '<br>',
233 _('(!) Consider performing a', wiki=True), ' ',
234 f.url(1, href=request.page.url(request, querydict, escape=0)),
235 _('full-text search with your search terms'),
236 f.url(0), '.',
237 ]) or ''), "error")
238 Page(request, pagename).send_page()
239 return
240
241 request.emit_http_headers()
242
243 # This action generates data using the user language
244 request.setContentLanguage(request.lang)
245
246 request.theme.send_title(title % needle, form=request.form, pagename=pagename)
247
248 # Start content (important for RTL support)
249 request.write(request.formatter.startContent("content"))
250
251 # Hints
252 f = request.formatter
253 hints = []
254
255 if titlesearch:
256 querydict = wikiutil.parseQueryString(request.query_string)
257 querydict.update({'titlesearch': 0})
258
259 hints.append(''.join([
260 _("(!) You're performing a title search that might not include"
261 ' all related results of your search query in this wiki. <<BR>>', wiki=True),
262 ' ',
263 f.url(1, href=request.page.url(request, querydict, escape=0)),
264 f.text(_('Click here to perform a full-text search with your '
265 'search terms!')),
266 f.url(0),
267 ]))
268
269 if advancedsearch and mtime_msg:
270 hints.append(mtime_msg)
271
272 if hints:
273 request.write(searchHints(f, hints))
274
275 # Search stats
276 request.write(results.stats(request, request.formatter, hitsFrom))
277
278 # Then search results
279 info = not titlesearch
280 if context:
281 output = results.pageListWithContext(request, request.formatter,
282 info=info, context=context, hitsFrom=hitsFrom, hitsInfo=1)
283 else:
284 output = results.pageList(request, request.formatter, info=info,
285 hitsFrom=hitsFrom, hitsInfo=1)
286
287 request.write(output)
288
289 request.write(request.formatter.endContent())
290 request.theme.send_footer(pagename)
291 request.theme.send_closing_html()
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.