diff --git a/search/indico_search/__init__.py b/search/indico_search/__init__.py
index d59cc09..c4a2c7e 100644
--- a/search/indico_search/__init__.py
+++ b/search/indico_search/__init__.py
@@ -14,6 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see .
-__all__ = ('SearchPluginBase',)
+__all__ = ('SearchPluginBase', 'SearchEngine')
-from .base import SearchPluginBase
+from .base import SearchPluginBase, SearchEngine
diff --git a/search/indico_search/base.py b/search/indico_search/base.py
index 604edf6..52a6b71 100644
--- a/search/indico_search/base.py
+++ b/search/indico_search/base.py
@@ -14,10 +14,12 @@
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see .
+from flask import session
from flask_pluginengine import depends
from indico.core.plugins import IndicoPlugin
+from indico_search.forms import SearchForm
from indico_search.plugin import SearchPlugin
@@ -25,6 +27,50 @@ from indico_search.plugin import SearchPlugin
class SearchPluginBase(IndicoPlugin):
"""Base class for search engine plugins"""
+ #: the SearchEngine subclass to use
+ engine_class = None
+ #: the SearchForm subclass to use
+ search_form = SearchForm
+
def init(self):
super(SearchPluginBase, self).init()
- SearchPlugin.instance.engine = self
+ SearchPlugin.instance.engine_plugin = self
+
+ @property
+ def only_public(self):
+ """If the search engine only returns public events"""
+ return session.user is None
+
+ def perform_search(self, values, obj=None, page=1):
+ """Performs the search.
+
+ For documentation on the parameters and return value, see
+ the documentation of the :class:`SearchEngine` class.
+ """
+ return self.engine_class(values, obj, page).process()
+
+
+class SearchEngine(object):
+ """Base class for a search engine"""
+
+ def __init__(self, values, obj, page):
+ """
+ :param values: the values sent by the user
+ :param obj: object to search in (a `Category` or `Conference`)
+ :param page: the result page to show (if supported)
+ """
+ self.values = values
+ self.obj = obj
+ self.page = page
+ self.user = session.user
+
+ def build_url(self, **query_params):
+ """Creates the URL for the search request"""
+ raise NotImplementedError
+
+ def process(self):
+ """Executes the search
+
+ :return: an object that's passed directly to the result template
+ """
+ raise NotImplementedError
diff --git a/search/indico_search/blueprint.py b/search/indico_search/blueprint.py
index 23f4a21..b85047b 100644
--- a/search/indico_search/blueprint.py
+++ b/search/indico_search/blueprint.py
@@ -18,4 +18,11 @@ from __future__ import unicode_literals
from indico.core.plugins import IndicoPluginBlueprint
+from indico_search.controllers import RHSearch
+
+
blueprint = IndicoPluginBlueprint('search', 'indico_search')
+
+blueprint.add_url_rule('/search', 'search', RHSearch, methods=('GET', 'POST'))
+blueprint.add_url_rule('/category//search', 'search', RHSearch, methods=('GET', 'POST'))
+blueprint.add_url_rule('/event//search', 'search', RHSearch, methods=('GET', 'POST'))
diff --git a/search/indico_search/controllers.py b/search/indico_search/controllers.py
new file mode 100644
index 0000000..8647ab6
--- /dev/null
+++ b/search/indico_search/controllers.py
@@ -0,0 +1,52 @@
+# This file is part of Indico.
+# Copyright (C) 2002 - 2014 European Organization for Nuclear Research (CERN).
+#
+# Indico is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# Indico is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Indico; if not, see .
+
+from __future__ import unicode_literals
+
+from flask import request, session
+from flask_pluginengine import current_plugin
+
+from MaKaC.conference import ConferenceHolder, Conference, CategoryManager
+from MaKaC.webinterface.rh.conferenceBase import RHCustomizable
+from indico_search.views import WPSearchCategory, WPSearchEvent
+
+
+class RHSearch(RHCustomizable):
+ def _checkParams(self):
+ if 'confId' in request.view_args:
+ self.obj = ConferenceHolder().getById(request.view_args['confId'])
+ self.obj_type = 'event'
+ elif 'categId' in request.view_args:
+ self.obj = CategoryManager().getById(request.view_args['categId'])
+ self.obj_type = 'category' if not self.obj.isRoot() else None
+ else:
+ self.obj = CategoryManager().getRoot()
+ self.obj_type = None
+
+ try:
+ self.page = int(request.values['page'])
+ except (ValueError, KeyError):
+ self.page = 1
+
+ def _process(self):
+ with current_plugin.engine_plugin.plugin_context():
+ form = current_plugin.search_form()
+ view_class = WPSearchEvent if isinstance(self.obj, Conference) else WPSearchCategory
+ result = None
+ if form.validate_on_submit():
+ result = current_plugin.perform_search(form.data, self.obj, self.page)
+ return view_class.render_template('results.html', self.obj, only_public=current_plugin.only_public,
+ form=form, obj_type=self.obj_type, result=result)
diff --git a/search/indico_search/forms.py b/search/indico_search/forms.py
new file mode 100644
index 0000000..5b0a6f0
--- /dev/null
+++ b/search/indico_search/forms.py
@@ -0,0 +1,40 @@
+# This file is part of Indico.
+# Copyright (C) 2002 - 2014 European Organization for Nuclear Research (CERN).
+#
+# Indico is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# Indico is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Indico; if not, see .
+
+from __future__ import unicode_literals
+
+from wtforms.ext.dateutil.fields import DateField
+from wtforms.fields.core import StringField, SelectField
+from wtforms.validators import Optional
+
+from indico.util.i18n import _
+from indico.util.string import strip_whitespace
+from indico.web.forms.base import IndicoForm
+
+
+FIELD_CHOICES = [('', _('Anywhere')),
+ ('title', _('Title')),
+ ('abstract', _('Description/Abstract')),
+ ('author', _('Author/Speaker')),
+ ('affiliation', _('Affiliation')),
+ ('keyword', _('Keyword'))]
+
+
+class SearchForm(IndicoForm):
+ phrase = StringField(_('Phrase'), filters=[strip_whitespace])
+ field = SelectField(_('Search in'), choices=FIELD_CHOICES)
+ start_date = DateField('Start Date', [Optional()], parse_kwargs={'dayfirst': True})
+ end_date = DateField('End Date', [Optional()], parse_kwargs={'dayfirst': True})
diff --git a/search/indico_search/plugin.py b/search/indico_search/plugin.py
index 613c7f2..fd1d46a 100644
--- a/search/indico_search/plugin.py
+++ b/search/indico_search/plugin.py
@@ -28,17 +28,17 @@ class SearchPlugin(IndicoPlugin):
"""
hidden = True
- _engine = None # the search engine plugin
+ _engine_plugin = None # the search engine plugin
@property
- def engine(self):
- return self._engine
+ def engine_plugin(self):
+ return self._engine_plugin
- @engine.setter
- def engine(self, value):
- if self._engine is not None:
- raise RuntimeError('Another search engine is active: {}'.format(self._engine.name))
- self._engine = value
+ @engine_plugin.setter
+ def engine_plugin(self, value):
+ if self._engine_plugin is not None:
+ raise RuntimeError('Another search engine plugin is active: {}'.format(self._engine_plugin.name))
+ self._engine_plugin = value
def get_blueprints(self):
return blueprint
diff --git a/search/indico_search/templates/results.html b/search/indico_search/templates/results.html
new file mode 100644
index 0000000..8f6a8aa
--- /dev/null
+++ b/search/indico_search/templates/results.html
@@ -0,0 +1,72 @@
+
+ {% if only_public %}
+
+ {% trans %}Warning: since you are not logged in, only results from public events will appear.{% endtrans %}
+
+ {% endif %}
+
+
+ {% trans %}Search{% endtrans %}
+ {% if obj_type == 'event' %}
+ {% trans %}Event{% endtrans %}
+ {% elif obj_type == 'category' %}
+ {% trans %}Category{% endtrans %}
+ {% endif %}
+
+
+
+
+{% block scripts %}{% endblock %}
diff --git a/search/indico_search/views.py b/search/indico_search/views.py
new file mode 100644
index 0000000..235e424
--- /dev/null
+++ b/search/indico_search/views.py
@@ -0,0 +1,31 @@
+# This file is part of Indico.
+# Copyright (C) 2002 - 2014 European Organization for Nuclear Research (CERN).
+#
+# Indico is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the
+# License, or (at your option) any later version.
+#
+# Indico is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Indico; if not, see .
+
+from __future__ import unicode_literals
+
+from indico.core.plugins import WPJinjaMixinPlugin
+from MaKaC.webinterface.pages.category import WPCategoryDisplayBase
+from MaKaC.webinterface.pages.conferences import WPConferenceDisplayBase
+
+
+class WPSearchCategory(WPJinjaMixinPlugin, WPCategoryDisplayBase):
+ def _getBody(self, params):
+ return self._getPageContent(params)
+
+
+class WPSearchEvent(WPJinjaMixinPlugin, WPConferenceDisplayBase):
+ def _getBody(self, params):
+ return self._getPageContent(params)