Example #1
0
class ISearchSettings(Interface):
    display_searchbox = schema.Bool(
        title=_(u"Display search box"),
        description=_(u"If this option is selected, a search input box "
                      u"is shown on the search page."),
        default=True,
    )

    collection = schema.TextLine(
        title=_(u"Collection"),
        description=_(u"You must define exactly one search collection."),
        required=True,
        default=u"default_collection",
    )

    frontend = schema.TextLine(
        title=_(u"Front end"),
        description=_(u"You must define exactly one front end."),
        required=True,
        default=u"default_frontend",
    )

    use_xslt_transform = schema.Bool(
        title=_(u"Use XSLT"),
        description=_(u"Apply an XSLT transform to search results "
                      u"instead of default view."),
        default=False)

    xslt_transform = schema.Text(
        title=_(u"XSLT transform"),
        description=_(u"This transform is applied to transform the "
                      u"search results document into HTML."),
        default=u"",
        required=False,
    )
Example #2
0
class EditForm(controlpanel.RegistryEditForm):
    schema = ISettings
    fields = field.Fields(IGeneralSettings)
    groups = ConnectionSettingsGroup, SearchSettingsGroup
    label = _(u"Settings for integration with Google Search Appliance")

    def getContent(self):
        return AbstractRecordsProxy(self.schema)
Example #3
0
 def _make_request(self, query):
     conn = get_connection()
     try:
         conn.request(
             "GET", "/search?%s" % urllib.urlencode(query), headers={"Accept-language": self.get_language()}
         )
         response = conn.getresponse()
     except IOError, exc:
         self.error = _("Search is unavailable: ${message}.", mapping={"message": str(exc)})
         raise
Example #4
0
 def _make_request(self, query):
     conn = get_connection()
     try:
         conn.request("GET",
                      "/search?%s" % urllib.urlencode(query),
                      headers={
                          'Accept-language': self.get_language(),
                      })
         response = conn.getresponse()
     except IOError, exc:
         self.error = _("Search is unavailable: ${message}.",
                        mapping={'message': str(exc)})
         raise
Example #5
0
class SearchView(BrowserView):
    """Search view.

    The functionality is split out into smaller methods and properties
    to allow easy customization.

    In particular ``build_query`` returns the query that is sent to
    the GSA to request search results.
    """

    template = ViewPageTemplateFile("search.pt")

    error = None

    estimated_results = 0

    @property
    def __call__(self):
        if self.enabled:
            return self.template

        # fall back to default search skin
        skin = self.context.portal_skins.getSkin()
        template = getattr(skin, 'search', None)

        # it may not exist
        if template is None:
            raise NotFound('search')

        # aq-wrap in current context and return
        return template.__of__(self.context)

    @property
    def enabled(self):
        registry = component.getUtility(IRegistry)
        settings = registry.forInterface(IGeneralSettings)
        return settings.enabled

    @memoize_contextless
    def get_settings(self):
        registry = component.getUtility(IRegistry)
        return registry.forInterface(ISearchSettings)

    def get_collection(self):
        return self.get_settings().collection

    def get_frontend(self):
        return self.get_settings().frontend

    @property
    def display_searchbox(self):
        return self.get_settings().display_searchbox

    @memoize_contextless
    def get_language(self):
        return self.portal_state.language().encode('utf-8')

    @property
    def use_transform(self):
        return self.get_settings().use_xslt_transform

    @property
    def search_terms(self):
        return self.request.form.get('SearchableText') or \
               self.request.form.get('q', '')

    @property
    def search_query(self):
        return self.query['q']

    @property
    @memoize_contextless
    def query(self):
        return self.build_query()

    @property
    @memoize_contextless
    def results(self):
        iter = self.iter_results()
        return tuple(iter)

    @property
    @memoize_contextless
    def url(self):
        return self.request.getURL()

    @property
    @memoize_contextless
    def portal_state(self):
        context = aq_inner(self.context)
        return component.getMultiAdapter((context, self.request),
                                         name=u'plone_portal_state')

    @property
    def dynamic_navigation(self):
        results = []

        document = self._get_results()
        for element in document.findall('.//PMT'):
            results.append(
                (element.attrib['NM'], element.attrib['DN'],
                 dict((category.attrib['V'], int(category.attrib['C']))
                      for category in element.findall('PV'))))

        return results

    def build_query(self):
        query = self.request.form.copy()

        # main query
        query['q'] = self.search_terms

        # determine current language
        query['hl'] = self.get_language()

        # request full metadata fields
        query['getfields'] = '*'

        # XML output
        query['output'] = 'xml_no_dtd'

        # encoding
        query['ie'] = 'UTF-8'
        query['oe'] = 'UTF-8'

        # search collection
        query['site'] = self.get_collection()

        # search frontend
        query['client'] = self.get_frontend()

        # only public access is supported
        query['access'] = 'p'

        # don't filter results
        query['filter'] = 0

        return query

    @memoize_contextless
    def _get_results(self):
        t = time.time()

        try:
            response = self._make_request(self.query)

            if response.status == 200:
                document = lxml.etree.parse(response)
                elapsed = time.time() - t

                try:
                    self.estimated_results = int(document.find('.//M').text)
                    query_time = float(document.find('.//TM').text)
                except AttributeError:
                    query_time = -1

                log.info("received %d search results in %3.3f seconds " %
                         (self.estimated_results, elapsed) +
                         "(query time: %3.3f seconds)." % query_time)

                return document
            else:
                reason = "Bad server response (%d %s)" % (response.status,
                                                          response.reason)
                log.warn(reason)
        except IOError, exc:
            log.warn(exc)
            reason = str(exc)

        self.error = _("An error occurred during search: ${message}.",
                       mapping={'message': reason})

        return trivial_search
Example #6
0
class SearchSettingsGroup(group.Group):
    label = _(u"Search settings")
    fields = field.Fields(ISearchSettings)
Example #7
0
class ConnectionSettingsGroup(group.Group):
    label = _(u"Connection settings")
    fields = field.Fields(IConnectionSettings)
Example #8
0
class IConnectionSettings(Interface):
    name = schema.TextLine(title=_(u"Data source name"),
                           description=_(
                               u"This identifies the data source within the "
                               u"search appliance."),
                           required=True,
                           default=u"plone")

    host = schema.TextLine(
        title=_(u"Host"),
        description=_(u"The hostname or IP-address of the appliance "
                      u"(e.g. 192.168.1.200, \"gsa.local\")."),
        required=True,
        default=u"",
    )

    feed_protocol_port = schema.Int(
        title=_(u"Feed protocol port"),
        description=_(u"The network port for the feed protocol service. "
                      u"Normally you do not need to change this."),
        default=19900,
        required=True,
    )

    use_secure_search = schema.Bool(
        title=_(u"Secure search"),
        description=_(u"Use SSL-encrypted search (recommended). "
                      u"You should disable this only if the appliance is "
                      u"located on a private network."),
        default=True)

    unsecured_search_port = schema.Int(
        title=_(u"HTTP search port"),
        description=_(u"The network port for the unsecured search service. "
                      u"This service runs on HTTP."),
        default=80,
        required=True,
    )

    secured_search_port = schema.Int(
        title=_(u"HTTPS search port"),
        description=_(u"The network port for the unsecured search service. "
                      u"This service runs on HTTPS."),
        default=443,
        required=True,
    )

    timeout = schema.Int(
        title=_(u"Time out"),
        description=_(u"The connection time-out limit in seconds."),
        default=3,
        required=True,
    )
Example #9
0
class IGeneralSettings(Interface):
    enabled = schema.Bool(
        title=_(u"Enable"),
        description=_(u"Integration with the Google Search Appliance is only "
                      u"active when this field is set."),
        default=True)