1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import pkg_resources
20 import re
21
22 from genshi.builder import tag
23
24 from trac.attachment import AttachmentModule, Attachment
25 from trac.config import IntOption
26 from trac.core import *
27 from trac.mimeview.api import IContentConverter, Mimeview
28 from trac.perm import IPermissionPolicy, IPermissionRequestor
29 from trac.resource import *
30 from trac.search import ISearchSource, search_to_sql, shorten_result
31 from trac.timeline.api import ITimelineEventProvider
32 from trac.util import as_int, get_reporter_id
33 from trac.util.datefmt import from_utimestamp, to_utimestamp
34 from trac.util.text import shorten_line
35 from trac.util.translation import _, tag_
36 from trac.versioncontrol.diff import get_diff_options, diff_blocks
37 from trac.web.api import HTTPBadRequest, IRequestHandler
38 from trac.web.chrome import (Chrome, INavigationContributor,
39 ITemplateProvider, add_ctxtnav, add_link,
40 add_notice, add_script, add_stylesheet,
41 add_warning, prevnext_nav, web_context)
42 from trac.wiki.api import IWikiPageManipulator, WikiSystem, validate_page_name
43 from trac.wiki.formatter import format_to, OneLinerFormatter
44 from trac.wiki.model import WikiPage
45
46
48
49 implements(IContentConverter, INavigationContributor,
50 IPermissionRequestor, IRequestHandler, ITimelineEventProvider,
51 ISearchSource, ITemplateProvider)
52
53 page_manipulators = ExtensionPoint(IWikiPageManipulator)
54
55 realm = WikiSystem.realm
56
57 max_size = IntOption('wiki', 'max_size', 262144,
58 """Maximum allowed wiki page size in characters.""")
59
60 default_edit_area_height = IntOption('wiki', 'default_edit_area_height',
61 20,
62 """Default height of the textarea on the wiki edit page.
63 (//Since 1.1.5//)""")
64
65 PAGE_TEMPLATES_PREFIX = 'PageTemplates/'
66 DEFAULT_PAGE_TEMPLATE = 'DefaultPage'
67
68
69
71 yield ('txt', _("Plain Text"), 'txt', 'text/x-trac-wiki',
72 'text/plain', 9)
73
74 - def convert_content(self, req, mimetype, content, key):
75 return content, 'text/plain;charset=utf-8'
76
77
78
81
83 if 'WIKI_VIEW' in req.perm(self.realm, 'WikiStart'):
84 yield ('mainnav', 'wiki',
85 tag.a(_("Wiki"), href=req.href.wiki(), accesskey=1))
86 if 'WIKI_VIEW' in req.perm(self.realm, 'TracGuide'):
87 yield ('metanav', 'help',
88 tag.a(_("Help/Guide"), href=req.href.wiki('TracGuide'),
89 accesskey=6))
90
91
92
94 actions = ['WIKI_CREATE', 'WIKI_DELETE', 'WIKI_MODIFY', 'WIKI_RENAME',
95 'WIKI_VIEW']
96 return actions + [('WIKI_ADMIN', actions)]
97
98
99
101 match = re.match(r'/wiki(?:/(.+))?$', req.path_info)
102 if match:
103 if match.group(1):
104 req.args['page'] = match.group(1)
105 return 1
106
108 action = req.args.get('action', 'view')
109 pagename = req.args.get('page', 'WikiStart')
110 version = req.args.getint('version')
111 old_version = req.args.getint('old_version')
112
113 if pagename.startswith('/') or pagename.endswith('/') or \
114 '//' in pagename:
115 pagename = re.sub(r'/{2,}', '/', pagename.strip('/'))
116 req.redirect(req.href.wiki(pagename))
117 if not validate_page_name(pagename):
118 raise TracError(_("Invalid Wiki page name '%(name)s'",
119 name=pagename))
120
121 page = WikiPage(self.env, pagename)
122 versioned_page = WikiPage(self.env, pagename, version)
123
124 req.perm(versioned_page.resource).require('WIKI_VIEW')
125
126 if version and versioned_page.version != version:
127 raise ResourceNotFound(
128 _('No version "%(num)s" for Wiki page "%(name)s"',
129 num=version, name=page.name))
130
131 add_stylesheet(req, 'common/css/wiki.css')
132
133 if req.method == 'POST':
134 if action == 'edit':
135 if 'cancel' in req.args:
136 req.redirect(req.href.wiki(page.name))
137
138 has_collision = version != page.version
139 for a in ('preview', 'diff', 'merge'):
140 if a in req.args:
141 action = a
142 break
143 versioned_page.text = req.args.get('text')
144 valid = self._validate(req, versioned_page)
145 if action == 'edit' and not has_collision and valid:
146 return self._do_save(req, versioned_page)
147 else:
148 return self._render_editor(req, page, action,
149 has_collision)
150 elif action == 'edit_comment':
151 self._do_edit_comment(req, versioned_page)
152 elif action == 'delete':
153 self._do_delete(req, versioned_page)
154 elif action == 'rename':
155 return self._do_rename(req, page)
156 elif action == 'diff':
157 style, options, diff_data = get_diff_options(req)
158 contextall = diff_data['options']['contextall']
159 req.redirect(req.href.wiki(versioned_page.name, action='diff',
160 old_version=old_version,
161 version=version,
162 contextall=contextall or None))
163 else:
164 raise HTTPBadRequest(_("Invalid request arguments."))
165 elif action == 'delete':
166 return self._render_confirm_delete(req, page)
167 elif action == 'rename':
168 return self._render_confirm_rename(req, page)
169 elif action == 'edit':
170 return self._render_editor(req, page)
171 elif action == 'edit_comment':
172 return self._render_edit_comment(req, versioned_page)
173 elif action == 'diff':
174 return self._render_diff(req, versioned_page)
175 elif action == 'history':
176 return self._render_history(req, versioned_page)
177 else:
178 format = req.args.get('format')
179 if format:
180 Mimeview(self.env).send_converted(req, 'text/x-trac-wiki',
181 versioned_page.text,
182 format, versioned_page.name)
183 return self._render_view(req, versioned_page)
184
185
186
189
191 return [pkg_resources.resource_filename('trac.wiki', 'templates')]
192
193
194
196 valid = True
197
198
199 if len(req.args.get('text', '')) > self.max_size:
200 add_warning(req, _("The wiki page is too long (must be less "
201 "than %(num)s characters)",
202 num=self.max_size))
203 valid = False
204
205
206 for manipulator in self.page_manipulators:
207 for field, message in manipulator.validate_wiki_page(req, page):
208 valid = False
209 if field:
210 add_warning(req, tag_("The Wiki page field %(field)s"
211 " is invalid: %(message)s",
212 field=tag.strong(field),
213 message=message))
214 else:
215 add_warning(req, tag_("Invalid Wiki page: %(message)s",
216 message=message))
217 return valid
218
219 - def _page_data(self, req, page, action=''):
220 title = get_resource_summary(self.env, page.resource)
221 if action:
222 title += ' (%s)' % action
223 return {'page': page, 'action': action, 'title': title}
224
225 - def _prepare_diff(self, req, page, old_text, new_text,
226 old_version, new_version):
227 diff_style, diff_options, diff_data = get_diff_options(req)
228 diff_context = 3
229 for option in diff_options:
230 if option.startswith('-U'):
231 diff_context = int(option[2:])
232 break
233 if diff_context < 0:
234 diff_context = None
235 diffs = diff_blocks(old_text, new_text, context=diff_context,
236 ignore_blank_lines='-B' in diff_options,
237 ignore_case='-i' in diff_options,
238 ignore_space_changes='-b' in diff_options)
239 def version_info(v, last=0):
240 return {'path': get_resource_name(self.env, page.resource),
241
242 'rev': v or _("currently edited"),
243 'shortrev': v or last + 1,
244 'href': req.href.wiki(page.name, version=v)
245 if v else None}
246 changes = [{'diffs': diffs, 'props': [],
247 'new': version_info(new_version, old_version),
248 'old': version_info(old_version)}]
249
250 add_stylesheet(req, 'common/css/diff.css')
251 add_script(req, 'common/js/diff.js')
252 return diff_data, changes
253
267
269 req.perm(page.resource).require('WIKI_DELETE')
270
271 if 'cancel' in req.args:
272 req.redirect(get_resource_url(self.env, page.resource, req.href))
273
274 version = req.args.getint('version')
275 old_version = req.args.getint('old_version', version)
276
277 with self.env.db_transaction:
278 if version and old_version and version > old_version:
279
280 for v in range(old_version, version):
281 page.delete(v + 1)
282 else:
283
284 page.delete(version)
285
286 if not page.exists:
287 add_notice(req, _("The page %(name)s has been deleted.",
288 name=page.name))
289 req.redirect(req.href.wiki())
290 else:
291 if version and old_version and version > old_version + 1:
292 add_notice(req, _("The versions %(from_)d to %(to)d of the "
293 "page %(name)s have been deleted.",
294 from_=old_version + 1, to=version, name=page.name))
295 else:
296 add_notice(req, _("The version %(version)d of the page "
297 "%(name)s has been deleted.",
298 version=version, name=page.name))
299 req.redirect(req.href.wiki(page.name))
300
302 req.perm(page.resource).require('WIKI_RENAME')
303
304 if 'cancel' in req.args:
305 req.redirect(get_resource_url(self.env, page.resource, req.href))
306
307 old_name, old_version = page.name, page.version
308 new_name = req.args.get('new_name', '')
309 new_name = re.sub(r'/{2,}', '/', new_name.strip('/'))
310 redirect = req.args.get('redirect')
311
312
313 warn = None
314 if not new_name:
315 warn = _("A new name is mandatory for a rename.")
316 elif not validate_page_name(new_name):
317 warn = _("The new name is invalid (a name which is separated "
318 "with slashes cannot be '.' or '..').")
319 elif new_name == old_name:
320 warn = _("The new name must be different from the old name.")
321 elif WikiPage(self.env, new_name).exists:
322 warn = _("The page %(name)s already exists.", name=new_name)
323 if warn:
324 add_warning(req, warn)
325 return self._render_confirm_rename(req, page, new_name)
326
327 with self.env.db_transaction as db:
328 page.rename(new_name)
329 if redirect:
330 redirection = WikiPage(self.env, old_name)
331 redirection.text = _('See [wiki:"%(name)s"].', name=new_name)
332 author = get_reporter_id(req)
333 comment = u'[wiki:"%s@%d" %s] \u2192 [wiki:"%s"].' % (
334 new_name, old_version, old_name, new_name)
335 redirection.save(author, comment, req.remote_addr)
336
337 add_notice(req, _("The page %(old_name)s has been renamed to "
338 "%(new_name)s.", old_name=old_name,
339 new_name=new_name))
340 if redirect:
341 add_notice(req, _("The page %(old_name)s has been recreated "
342 "with a redirect to %(new_name)s.",
343 old_name=old_name, new_name=new_name))
344
345 req.redirect(req.href.wiki(old_name if redirect else new_name))
346
348 if not page.exists:
349 req.perm(page.resource).require('WIKI_CREATE')
350 else:
351 req.perm(page.resource).require('WIKI_MODIFY')
352
353 if 'WIKI_ADMIN' in req.perm(page.resource):
354
355
356 page.readonly = int('readonly' in req.args)
357
358 try:
359 page.save(get_reporter_id(req, 'author'), req.args.get('comment'),
360 req.remote_addr)
361 except TracError:
362 add_warning(req, _("Page not modified, showing latest version."))
363 return self._render_view(req, page)
364
365 href = req.href.wiki(page.name, action='diff', version=page.version)
366 add_notice(req, tag_("Your changes have been saved in version "
367 "%(version)s (%(diff)s).", version=page.version,
368 diff=tag.a(_("diff"), href=href)))
369 req.redirect(get_resource_url(self.env, page.resource, req.href,
370 version=None))
371
373 req.perm(page.resource).require('WIKI_DELETE')
374
375 version = None
376 if 'delete_version' in req.args:
377 version = req.args.getint('version', 0)
378 old_version = req.args.getint('old_version', version)
379
380 what = 'multiple' if version and old_version \
381 and version - old_version > 1 \
382 else 'single' if version else 'page'
383
384 num_versions = 0
385 new_date = None
386 old_date = None
387 for v, t, author, comment, ipnr in page.get_history():
388 if (v <= version or what == 'page') and new_date is None:
389 new_date = t
390 if (v <= old_version and what == 'multiple' or
391 num_versions > 1 and what == 'single'):
392 break
393 num_versions += 1
394 old_date = t
395
396 data = self._page_data(req, page, 'delete')
397 attachments = Attachment.select(self.env, self.realm, page.name)
398 data.update({
399 'what': what, 'new_version': None, 'old_version': None,
400 'num_versions': num_versions, 'new_date': new_date,
401 'old_date': old_date, 'attachments': list(attachments),
402 })
403 if version is not None:
404 data.update({'new_version': version, 'old_version': old_version})
405 self._wiki_ctxtnav(req, page)
406 return 'wiki_delete.html', data, None
407
409 req.perm(page.resource).require('WIKI_RENAME')
410
411 data = self._page_data(req, page, 'rename')
412 data['new_name'] = new_name if new_name is not None else page.name
413 self._wiki_ctxtnav(req, page)
414 return 'wiki_rename.html', data, None
415
417 if not page.exists:
418 raise TracError(_("Version %(num)s of page \"%(name)s\" does not "
419 "exist",
420 num=req.args.get('version'), name=page.name))
421
422 old_version = req.args.getint('old_version')
423 if old_version:
424 if old_version == page.version:
425 old_version = None
426 elif old_version > page.version:
427
428 old_version = page.resource.version
429 page = WikiPage(self.env, page.name, old_version)
430 req.perm(page.resource).require('WIKI_VIEW')
431 latest_page = WikiPage(self.env, page.name)
432 req.perm(latest_page.resource).require('WIKI_VIEW')
433 new_version = page.version
434
435 date = author = comment = ipnr = None
436 num_changes = 0
437 prev_version = next_version = None
438 for version, t, a, c, i in latest_page.get_history():
439 if version == new_version:
440 date = t
441 author = a or 'anonymous'
442 comment = c or '--'
443 ipnr = i or ''
444 else:
445 if version < new_version:
446 num_changes += 1
447 if not prev_version:
448 prev_version = version
449 if old_version is None or version == old_version:
450 old_version = version
451 break
452 else:
453 next_version = version
454 if not old_version:
455 old_version = 0
456 old_page = WikiPage(self.env, page.name, old_version)
457 req.perm(old_page.resource).require('WIKI_VIEW')
458
459
460 old_text = old_page.text.splitlines()
461 new_text = page.text.splitlines()
462 diff_data, changes = self._prepare_diff(req, page, old_text, new_text,
463 old_version, new_version)
464
465
466 if prev_version:
467 add_link(req, 'prev', req.href.wiki(page.name, action='diff',
468 version=prev_version),
469 _("Version %(num)s", num=prev_version))
470 add_link(req, 'up', req.href.wiki(page.name, action='history'),
471 _('Page history'))
472 if next_version:
473 add_link(req, 'next', req.href.wiki(page.name, action='diff',
474 version=next_version),
475 _("Version %(num)s", num=next_version))
476
477 data = self._page_data(req, page, 'diff')
478 data.update({
479 'change': {'date': date, 'author': author, 'ipnr': ipnr,
480 'comment': comment},
481 'new_version': new_version, 'old_version': old_version,
482 'latest_version': latest_page.version,
483 'num_changes': num_changes,
484 'longcol': 'Version', 'shortcol': 'v',
485 'changes': changes,
486 'diff': diff_data,
487 })
488 prevnext_nav(req, _("Previous Change"), _("Next Change"),
489 _("Wiki History"))
490 return 'wiki_diff.html', data, None
491
492 - def _render_editor(self, req, page, action='edit', has_collision=False):
493 if has_collision:
494 if action == 'merge':
495 page = WikiPage(self.env, page.name)
496 req.perm(page.resource).require('WIKI_VIEW')
497 else:
498 action = 'collision'
499
500 if not page.exists:
501 req.perm(page.resource).require('WIKI_CREATE')
502 else:
503 req.perm(page.resource).require('WIKI_MODIFY')
504 original_text = page.text
505 comment = req.args.get('comment', '')
506 if 'text' in req.args:
507 page.text = req.args.get('text')
508 elif 'template' in req.args:
509 template = self.PAGE_TEMPLATES_PREFIX + req.args.get('template')
510 template_page = WikiPage(self.env, template)
511 if template_page and template_page.exists and \
512 'WIKI_VIEW' in req.perm(template_page.resource):
513 page.text = template_page.text
514 elif 'version' in req.args:
515 version = req.args.getint('version')
516 old_page = WikiPage(self.env, page.name, version)
517 req.perm(page.resource).require('WIKI_VIEW')
518 page.text = old_page.text
519 comment = _("Reverted to version %(version)s.", version=version)
520 if action in ('preview', 'diff'):
521 page.readonly = 'readonly' in req.args
522
523 author = get_reporter_id(req, 'author')
524 defaults = {'editrows': str(self.default_edit_area_height)}
525 prefs = dict((key, req.session.get('wiki_%s' % key, defaults.get(key)))
526 for key in ('editrows', 'sidebyside'))
527
528 if 'from_editor' in req.args:
529 sidebyside = req.args.get('sidebyside') or None
530 if sidebyside != prefs['sidebyside']:
531 req.session.set('wiki_sidebyside', int(bool(sidebyside)), 0)
532 else:
533 sidebyside = prefs['sidebyside']
534
535 if sidebyside:
536 editrows = max(int(prefs['editrows']),
537 len(page.text.splitlines()) + 1)
538 else:
539 editrows = req.args.get('editrows')
540 if editrows:
541 if editrows != prefs['editrows']:
542 req.session.set('wiki_editrows', editrows,
543 defaults['editrows'])
544 else:
545 editrows = prefs['editrows']
546
547 data = self._page_data(req, page, action)
548 context = web_context(req, page.resource)
549 data.update({
550 'context': context,
551 'author': author,
552 'comment': comment,
553 'edit_rows': editrows,
554 'sidebyside': sidebyside,
555 'scroll_bar_pos': req.args.get('scroll_bar_pos', ''),
556 'diff': None,
557 'attachments': AttachmentModule(self.env).attachment_data(context),
558 'show_readonly_checkbox': ReadonlyWikiPolicy.__name__ in
559 self.config.get('trac',
560 'permission_policies')
561 })
562 if action in ('diff', 'merge'):
563 old_text = original_text.splitlines() if original_text else []
564 new_text = page.text.splitlines() if page.text else []
565 diff_data, changes = self._prepare_diff(
566 req, page, old_text, new_text, page.version, '')
567 data.update({'diff': diff_data, 'changes': changes,
568 'action': 'preview', 'merge': action == 'merge',
569 'longcol': 'Version', 'shortcol': 'v'})
570 elif sidebyside and action != 'collision':
571 data['action'] = 'preview'
572
573 self._wiki_ctxtnav(req, page)
574 Chrome(self.env).add_wiki_toolbars(req)
575 Chrome(self.env).add_auto_preview(req)
576 add_script(req, 'common/js/folding.js')
577 return 'wiki_edit.html', data, None
578
584
585 - def _render_history(self, req, page):
586 """Extract the complete history for a given page.
587
588 This information is used to present a changelog/history for a given
589 page.
590 """
591 if not page.exists:
592 raise TracError(_("Page %(name)s does not exist", name=page.name))
593
594 data = self._page_data(req, page, 'history')
595
596 history = []
597 for version, date, author, comment, ipnr in page.get_history():
598 history.append({
599 'version': version,
600 'date': date,
601 'author': author,
602 'comment': comment,
603 'ipnr': ipnr
604 })
605 data.update({
606 'history': history,
607 'resource': page.resource,
608 'can_edit_comment': 'WIKI_ADMIN' in req.perm(page.resource)
609 })
610 add_ctxtnav(req, _("Back to %(wikipage)s", wikipage=page.name),
611 req.href.wiki(page.name))
612 return 'history_view.html', data, None
613
615 version = page.resource.version
616
617
618 if page.exists:
619 for conversion in Mimeview(self.env) \
620 .get_supported_conversions('text/x-trac-wiki'):
621 conversion_href = req.href.wiki(page.name, version=version,
622 format=conversion.key)
623 add_link(req, 'alternate', conversion_href, conversion.name,
624 conversion.in_mimetype)
625
626 data = self._page_data(req, page)
627 if page.name == 'WikiStart':
628 data['title'] = ''
629
630 ws = WikiSystem(self.env)
631 context = web_context(req, page.resource)
632 higher, related = [], []
633 if not page.exists:
634 if 'WIKI_CREATE' not in req.perm(page.resource):
635 raise ResourceNotFound(_("Page %(name)s not found",
636 name=page.name))
637 formatter = OneLinerFormatter(self.env, context)
638 if '/' in page.name:
639 parts = page.name.split('/')
640 for i in range(len(parts) - 2, -1, -1):
641 name = '/'.join(parts[:i] + [parts[-1]])
642 if not ws.has_page(name):
643 higher.append(ws._format_link(formatter, 'wiki',
644 '/' + name, name, False))
645 else:
646 name = page.name
647 name = name.lower()
648 related = [each for each in ws.pages
649 if name in each.lower()
650 and 'WIKI_VIEW' in req.perm(self.realm, each)]
651 related.sort()
652 related = [ws._format_link(formatter, 'wiki', '/' + each, each,
653 False)
654 for each in related]
655
656 latest_page = WikiPage(self.env, page.name)
657
658 prev_version = next_version = None
659 if version:
660 version = as_int(version, None)
661 if version is not None:
662 for hist in latest_page.get_history():
663 v = hist[0]
664 if v != version:
665 if v < version:
666 if not prev_version:
667 prev_version = v
668 break
669 else:
670 next_version = v
671
672 prefix = self.PAGE_TEMPLATES_PREFIX
673 templates = [template[len(prefix):]
674 for template in ws.get_pages(prefix)
675 if 'WIKI_VIEW' in req.perm(self.realm, template)]
676
677
678 if prev_version:
679 add_link(req, 'prev',
680 req.href.wiki(page.name, version=prev_version),
681 _("Version %(num)s", num=prev_version))
682
683 parent = None
684 if version:
685 add_link(req, 'up', req.href.wiki(page.name, version=None),
686 _("View latest version"))
687 elif '/' in page.name:
688 parent = page.name[:page.name.rindex('/')]
689 add_link(req, 'up', req.href.wiki(parent, version=None),
690 _("View parent page"))
691
692 if next_version:
693 add_link(req, 'next',
694 req.href.wiki(page.name, version=next_version),
695 _('Version %(num)s', num=next_version))
696
697
698 if version:
699 prevnext_nav(req, _("Previous Version"), _("Next Version"),
700 _("View Latest Version"))
701 else:
702 if parent:
703 add_ctxtnav(req, _('Up'), req.href.wiki(parent))
704 self._wiki_ctxtnav(req, page)
705
706
707 fields = {'text': page.text}
708 for manipulator in self.page_manipulators:
709 manipulator.prepare_wiki_page(req, page, fields)
710 text = fields.get('text', '')
711
712 data.update({
713 'context': context,
714 'text': text,
715 'latest_version': latest_page.version,
716 'attachments': AttachmentModule(self.env).attachment_data(context),
717 'default_template': self.DEFAULT_PAGE_TEMPLATE,
718 'templates': templates,
719 'version': version,
720 'higher': higher, 'related': related,
721 'resourcepath_template': 'wiki_page_path.html',
722 })
723 add_script(req, 'common/js/folding.js')
724 return 'wiki_view.html', data, None
725
735
736
737
739 if 'WIKI_VIEW' in req.perm:
740 yield ('wiki', _('Wiki changes'))
741
743 if 'wiki' in filters:
744 wiki_realm = Resource(self.realm)
745 for ts, name, comment, author, version in self.env.db_query("""
746 SELECT time, name, comment, author, version FROM wiki
747 WHERE time>=%s AND time<=%s
748 """, (to_utimestamp(start), to_utimestamp(stop))):
749 wiki_page = wiki_realm(id=name, version=version)
750 if 'WIKI_VIEW' not in req.perm(wiki_page):
751 continue
752 yield ('wiki', from_utimestamp(ts), author,
753 (wiki_page, comment))
754
755
756 for event in AttachmentModule(self.env).get_timeline_events(
757 req, wiki_realm, start, stop):
758 yield event
759
761 wiki_page, comment = event[3]
762 if field == 'url':
763 return context.href.wiki(wiki_page.id, version=wiki_page.version)
764 elif field == 'title':
765 name = tag.em(get_resource_name(self.env, wiki_page))
766 if wiki_page.version > 1:
767 return tag_("%(page)s edited", page=name)
768 else:
769 return tag_("%(page)s created", page=name)
770 elif field == 'description':
771 markup = format_to(self.env, None,
772 context.child(resource=wiki_page), comment)
773 if wiki_page.version > 1:
774 diff_href = context.href.wiki(
775 wiki_page.id, version=wiki_page.version, action='diff')
776 markup = tag(markup,
777 " (", tag.a(_("diff"), href=diff_href), ")")
778 return markup
779
780
781
783 if 'WIKI_VIEW' in req.perm:
784 yield ('wiki', _('Wiki'))
785
787 if not 'wiki' in filters:
788 return
789 with self.env.db_query as db:
790 sql_query, args = search_to_sql(db, ['w1.name', 'w1.author',
791 'w1.text'], terms)
792 wiki_realm = Resource(self.realm)
793 for name, ts, author, text in db("""
794 SELECT w1.name, w1.time, w1.author, w1.text
795 FROM wiki w1,(SELECT name, max(version) AS ver
796 FROM wiki GROUP BY name) w2
797 WHERE w1.version = w2.ver AND w1.name = w2.name
798 AND """ + sql_query, args):
799 page = wiki_realm(id=name)
800 if 'WIKI_VIEW' in req.perm(page):
801 yield (get_resource_url(self.env, page, req.href),
802 '%s: %s' % (name, shorten_line(text)),
803 from_utimestamp(ts), author,
804 shorten_result(text, terms))
805
806
807 for result in AttachmentModule(self.env).get_search_results(
808 req, wiki_realm, terms):
809 yield result
810
811
828