source: MILK/trunk/milk_server/milk_server/controllers/browse/discovery.py @ 5986

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/MILK/trunk/milk_server/milk_server/controllers/browse/discovery.py@5986
Revision 5986, 30.3 KB checked in by sdonegan, 11 years ago (diff)

Updated to handle revised text search

Line 
1'''
2Controller for the discovery search functionality
3'''
4import socket, logging
5from paste.request import parse_querystring
6from ndg.common.src.clients.ws.discovery.discoveryserviceclient import DiscoveryServiceClient
7from ndg.common.src.clients.xmldb.eXist.searchclient import SearchClient
8from ndg.common.src.clients.http.vocabserverclient import VocabServerClient as VS
9from ndg.common.src.models.vocabtermdata import VocabTermData as VTD
10from ndg.common.src.models.ndgObject import ndgObject
11from ndg.common.src.models.DIF import DIF
12from ndg.common.src.lib.mailer import mailHandler
13from milk_server.lib.base import *
14from milk_server.lib.Date import *
15from milk_server.models.DiscoveryState import DiscoveryState, constraints
16from milk_server.controllers.home import HomeController
17import browserconstants as bc
18from milk_server.lib.Utilities import getURLConstraints
19import milk_server.lib.constants as constants
20
21
22class DiscoveryController(HomeController):
23    '''
24    Provides the pylons controller for NDG discovery
25    '''
26
27    def __setup(self):
28        '''
29        Common setup for controller methods
30        '''
31        self.cf=request.environ['ndgConfig']
32        self.inputs=dict(parse_querystring(request.environ))
33       
34        self.message=''
35        c.inputErrors = {}    # dict to store error messages
36       
37        c.discoveryUrl = h.url_for('discovery')
38                       
39   
40    def index(self):
41        '''
42        Main entry point for doing discovery searches
43        '''
44        self.__setup()
45       
46        # if inputs are not set: if the discovery mode is enabled, display
47        # the search screen, otherwise redirect to the default home page according
48        # to what milk mode is set (i.e. editor/browse)
49        if not self.inputs or 'ClearForm' in self.inputs:
50            if g.discoveryEnabled:
51                return self.__advancedPrompt()
52            else:
53                logging.info("Discovery mode not enabled - redirect to default")
54                return h.redirect_to(h.url_for('default'))
55       
56        self.__getInputs()
57
58       
59        if 'orderBy' not in self.inputs:
60            self.inputs['orderBy'] = g.orderByList[0]
61           
62           
63        #get list of human readable values for orderbylist - uses webHelpers, so use dict in browserConstants.py to do this matching vals from getLists call.
64        #nb. webhelpers suck so no wuse own construct of option vals based on bc.ORDERBY_SENSIBLE_NAMES
65        orderSensibleNames = bc.ORDERBY_SENSIBLE_NAMES
66        orderOrderingList = bc.ORDERING_KEY #now use this ordering key to provide ordering in list.
67             
68        optionList=[] # do it myself. who needs webHelpers anyway.#TODI: abstract a webhelpers class so can provide an orderlist as index etc (like we've done here).
69
70           
71        for orderSel in orderOrderingList:
72           
73            if orderSensibleNames[orderSel] in g.orderByList:
74               
75                #remember in webHelpers key is value to list, value is option value.. therefore need to swap
76                if self.inputs['orderBy'] == orderSensibleNames[orderSel]:
77                    optionList.append("<option selected=\"selected\" value=\"" + orderSensibleNames[orderSel] + "\">" + orderSel + "</option>")
78                else:           
79                    optionList.append("<option value=\"" + orderSensibleNames[orderSel] + "\">" + orderSel + "</option>")
80                               
81            else:
82               
83                optionList.append("<option value=\"" + orderSel + "\">" + orderSel + "</option>")             
84               
85       
86        #TODO - see above
87        #c.orderByList = h.options_for_select(g.orderByList, self.inputs['orderBy'])       
88        c.orderByList = optionList # see above comment on how much python sucks when it comes to dictionaries!  If you don't believe me uncomment above lines.
89
90        if 'orderDirection' not in self.inputs:
91            self.inputs['orderDirection'] = constants.ORDER_BY_DIRECTION[0]
92           
93        c.orderDirection = h.options_for_select(constants.ORDER_BY_DIRECTION,
94                                                self.inputs['orderDirection']) 
95       
96        # if any errors are found, return user to search page
97        if c.inputErrors:
98            return self.__advancedPrompt()
99
100        searchString = self.inputs['searchString']
101        if 'vocabTerm' in self.inputs and self.inputs['vocabTerm']:
102            searchString += " %s" %self.inputs['vocabTerm']
103           
104        # users can return to search page to refine the search inputs; in this case
105        # they will have a 'constrained' input
106        self.constraints = self.__buildconstraints(self.dateRange, self.bbox, self.scope,
107                                                   searchString, self.inputs['geoSearchType'])
108        if 'constrained' in self.inputs: 
109            return self.__advancedPrompt(searchConstraints = self.constraints)
110
111        # ok, now go do the search
112        try:
113            return self.__runSearch(searchString, self.inputs['textTarget'],
114                                    self.inputs['start'], self.inputs['howmany'], 
115                                    orderBy = self.inputs['orderBy'], 
116                                    orderDirection = self.inputs['orderDirection'],
117                                    scope = self.scope, dateRange = self.dateRange, 
118                                    bbox = self.bbox, geoSearch=self.inputs['geoSearchType'])
119        except Exception, e:
120            if g.debugModeOn == 'True':
121                raise e
122            else:
123                c.xml='Unexpected error: %s'%(str(e))
124                return render('error')
125
126
127    def __getInputs(self):
128        '''
129        Retrieve the user inputs and set defaults.  Values are stored in the
130        self.inputs dict
131        '''
132        logging.debug("Getting user inputs")
133       
134        # restore contraints from input, if set
135        if 'constraints' in self.inputs:
136            constraints = getURLConstraints(self.inputs['constraints'])
137            del self.inputs['constraints']
138            # NB, be careful not to overwrite newly passed in info
139            for key, val in constraints.items():
140                if key not in self.inputs:
141                    self.inputs[key] = val
142                   
143        if 'vocabTerm' in self.inputs and 'searchString' not in self.inputs:
144            self.inputs['searchString'] = ""
145           
146        # see if this is a discovery search or a more complicated search
147        if 'searchTarget' not in self.inputs: 
148            self.inputs['searchTarget']='Discovery'
149       
150        # set default for table paging, if not already set
151        # NB, url arguments need converting back to ints
152        if 'start' not in self.inputs:
153            self.inputs['start'] = 1
154        else:
155            self.inputs['start'] = int(self.inputs['start'])
156           
157        if 'howmany' not in self.inputs:
158            self.inputs['howmany'] = 10
159        else:
160            self.inputs['howmany'] = int(self.inputs['howmany'])
161           
162        # the simplest query we might get is a text search, in which case
163        # the inputs should be start, howmany and searchString (although
164        # maybe not in that order. The next simplest is one with
165        # a specified textTarget, after that we need all the inputs.
166        if 'searchString' in self.inputs and 'textTarget' not in self.inputs:
167            # it's a simple text search
168            self.inputs['textTarget']='All'
169
170        # the next simplest is one that includes texttarget as well ...
171        expected=['searchString','textTarget']
172        missingInputs = self.__checkform(expected)
173        if missingInputs:
174            if bc.INCOMPLETE_SEARCH_INPUT_MESSAGE not in c.inputErrors:
175                c.inputErrors[bc.INCOMPLETE_SEARCH_INPUT_MESSAGE] = []
176            c.inputErrors[bc.INCOMPLETE_SEARCH_INPUT_MESSAGE].extend(missingInputs)
177
178        self.__getSpatioTemporalInputs()
179       
180        logging.debug("User inputs retrieved")
181
182
183    def __getSpatioTemporalInputs(self):
184        '''
185        Get spatiotemporal input data - and set up any defaults, if required
186        '''
187        logging.debug("Getting spatiotemporal inputs")
188        if 'geoSearchType' not in self.inputs:
189            self.inputs['geoSearchType']='overlaps'
190
191        # now we add the defaults... this is kind of historical - NOT SURE THIS IS STILL NEEDED
192        if len(self.inputs)==6:
193            self.bbox=None
194            self.dateRange=None
195            self.scope=None
196            return
197       
198        if 'source' in self.inputs and self.inputs['source'] != 'All':
199            # NB, the WSDL expects a list
200            self.scope = [self.inputs['source']]
201        else:
202            self.scope = None
203           
204        missingInputs = self.__checkform(['bboxN','bboxE','bboxS','bboxW','geoSearchType'])
205        if missingInputs: 
206            self.bbox = None
207        else:
208            # default form has a global bounding box, NB, internal to this routine we use bbox=[N,W,E,S], not [W,S,E,N]!
209            self.bbox = [self.inputs['bboxN'], self.inputs['bboxW'],
210                         self.inputs['bboxE'], self.inputs['bboxS']]
211           
212            errors = self.__checkBBoxValidity(self.bbox)
213            if errors:
214                if bc.INVALID_BBOX_MESSAGE not in c.inputErrors:
215                    c.inputErrors[bc.INVALID_BBOX_MESSAGE] = []
216                c.inputErrors[bc.INVALID_BBOX_MESSAGE].extend(errors)
217               
218        #self.bbox = None
219       
220       
221        missingInputs = self.__checkform(['startDate', 'endDate'])
222        self.dateRange = None
223        if missingInputs:
224            self.dateRange = None
225        elif self.inputs['startDate'] and not self.inputs['endDate']:
226            c.inputErrors[bc.INCOMPLETE_DATERANGE_MESSAGE] = ['End date missing']
227        elif not self.inputs['startDate'] and self.inputs['endDate']:
228            c.inputErrors[bc.INCOMPLETE_DATERANGE_MESSAGE] = ['Start date missing']
229        elif self.inputs['startDate'] and self.inputs['endDate']:
230            dateError = None
231            try:
232                year, month, day = self.inputs['startDate'].split('/')
233                self.dateRange = [(day, month, year)]
234                year, month, day = self.inputs['endDate'].split('/')
235                self.dateRange.append((day, month, year))
236
237                if self.dateRange <> [("","",""),("","","")]:
238                    dateError = self.__checkdates(self.dateRange)
239                   
240                else: 
241                    self.dateRange = None
242                               
243            except:
244                dateError = 'Invalid date provided'
245
246            if dateError:
247                if bc.INVALID_DATERANGE_MESSAGE not in c.inputErrors:
248                    c.inputErrors[bc.INVALID_DATERANGE_MESSAGE] = []
249                c.inputErrors[bc.INVALID_DATERANGE_MESSAGE].append(dateError)
250       
251        logging.debug("Spatiotemporal inputs retrieved")
252
253
254    def __getSearchClient(self, clientType):
255        '''
256        Retrieve the appropriate client to complete the search
257        - currently supported are browse and discovery clients
258        @param clientType: type of search client to use.  Currently accepts,
259        'Discovery', 'Browse' and 'NumSim'
260        @raise ValueError if unrecognised search client entered
261        @return search client adhering to the ndg.common.clients.interfacesearchclient
262        interface
263        '''
264        logging.debug("Getting %s type search client" %clientType)
265        searchClient = None
266        if clientType =='Discovery':
267            logging.info(" - use Discovery service to complete search")
268            if g.discoveryServiceURL:
269                searchClient = DiscoveryServiceClient(HostAndPort = g.discoveryServiceURL)
270            else:
271                searchClient = DiscoveryServiceClient()
272               
273        elif clientType in ['Browse','NumSim']:
274            logging.info(" - use Browse service to complete search")
275            searchClient = SearchClient(dbHostName = g.localEXist,
276                                        configFileName = g.pwFile)
277        else:
278            raise ValueError("Unrecognised search type, '%s'" %clientType)
279       
280        logging.debug("- returning search client")
281        return searchClient
282       
283
284    def __runSearch(self, searchString, textTarget, start,
285                    howmany, orderBy = None, orderDirection = None, scope = None, 
286                    dateRange = None, bbox = None, geoSearch = 'overlaps'):
287        '''
288        Carry out a text search for <searchString>
289        in the <textTarget> where the accepted text target values are controlled
290        by the DiscoveryTemplate GUI, and are: All, Authors, Parameters
291        @param searchString: string to search for
292        @param textTarget: target of the search - either, 'All', 'Authors' or 'Parameters'
293        @param start: starting record to return
294        @param howmany: number of records to return
295        @keyword orderBy: Field to order results by - NB, must be one of the
296        getList('orderByFieldList') values
297        @keyword orderDirection: Direction the 'orderBy' results should be returned in
298        - NB, this is currently 'ascending' or 'descending'
299        @keyword scope: scope of search - either NERC, NERC_DDC, MDIP or DPPP. Default = None
300        @keyword dateRange: date range in format [startDate, endDate] where the
301        date objects are tuples with format (day, month, year). Default = None
302        @keyword bbox: Bounding box in format [N,W,E,S]. Default = None
303        @keyword geoSearch: type of spatial search. Defaults to 'overlaps'.
304        '''
305        logging.debug("Running text search with string, '%s'" %searchString)
306       
307        searchClient = self.__getSearchClient(self.inputs['searchTarget'])
308       
309        if self.inputs['searchTarget'] in ['Browse','NumSim']:
310            textTarget = self.inputs['searchTarget']
311            if textTarget == 'Browse':
312                # NB, this switches the searching to be done on atom format
313                # rather than moles1.3 format docs
314                textTarget = SearchClient.ATOM_TARGET#'ndg_B_metadata'
315           
316        # PJK 04/09/08 Handle errors more gracefully
317        #
318        # http://proj.badc.rl.ac.uk/ndg/ticket/984
319        try:
320            searchClient.search(searchString,
321                                start = start,
322                                howmany = howmany,
323                                target = textTarget,
324                                scope = scope,
325                                dateRange = dateRange,
326                                bbox = bbox,
327                                geoSearchType = geoSearch,
328                                orderBy = orderBy,
329                                orderDirection = orderDirection)
330        except socket.error, e:
331            logging.error("Socket error for discovery service search: %s" % e)
332            c.xml='The Discovery Service is unavailable.  Please check with '+\
333                    'your system administrator'
334            return render('error')
335        except Exception, e:
336            logging.error("Calling discovery service search: %s" % e)
337            c.xml='An internal error occured.  Please check with ' + \
338                    'your system administrator'
339            return render('error')
340           
341        logging.debug("Search returned - now processing results")
342        # DiscoveryState object is a wrapper to the various search config
343        # variables
344        c.state = DiscoveryState(searchClient.serverSessionID, searchString,
345                                 request.environ, searchClient.hits, self.constraints,
346                                 start, howmany)
347
348        return self.__processSearchResults(searchClient, c.state)
349
350
351    def __processSearchResults(self, searchClient, ds):
352        '''
353        Process the results from a search - as ran by the input search client object
354        @param searchClient: search client adhering to the ndg.common.clients.interfacesearchclient
355        interface - which has just ran a search
356        @param ds: DiscoveryState object with info on the search
357        '''
358        if searchClient.error:
359            logging.error("Error encountered whilst running search: %s" %searchClient.error)
360            m=''
361            for i in searchClient.error:
362                m+='<p>%s</p>'%i
363            c.xml = m
364            return render('error')
365       
366       
367       
368        hits = searchClient.hits
369        # NB, this is used in the semantic search function of results.kid and short_results.kid
370        c.querystring = request.environ['QUERY_STRING']
371       
372       
373        c.altSearchURL = '%s?%s'%(h.url_for(action='semantic'),
374                                  request.environ['QUERY_STRING'])
375       
376        difs = []
377        errors = []
378
379        if hits == 0 and ds.constraintsInstance['textTarget'] != SearchClient.ATOM_TARGET:
380            outMessage = 'No records found for "%s"[constraints: %s]' \
381                %(ds.searchString, ds.constraints)
382            logging.info(outMessage) 
383            c.xml='<p>' + outMessage + '</p>'
384
385        else:
386            try:
387                # display browse search results differently
388                if self.inputs['searchTarget'] != 'Discovery':
389                    return self.__displayBrowseSearchResults(searchClient)
390   
391                # now actually retrieve the search records
392               
393                results = searchClient.getLabelledDocs(format='DIF')
394                               
395               
396                if not results:
397                    c.xml='<p>No results for "%s"!</p>'%ds.searchString
398                   
399                else:
400                    for result in results:
401                       
402                        obj=ndgObject(result[0], config = self.cf)
403                        try:
404                           
405                            difs.append(DIF(result[1],ndgObj=obj))
406                           
407                        except ValueError,e:
408                           
409                            errors.append((result[0], str(e)))
410       
411                    if not difs:
412                        c.xml='<p>No usable results for "%s"!</p>'%ds.searchString
413                   
414                    elif errors:
415                        c.xml='<p>Search results for "%s"'%ds.searchString
416                        dp=[]
417                        for e in errors:
418                            n=ndgObject(e[0])
419                            if n.repository not in dp: 
420                                dp.append(n.repository)
421                        if len(dp)<>1: 
422                            dp='[Various Data Providers]'
423                        else:
424                            dp='[%s]'%dp[0] 
425                           
426                        c.xml+=' (unfortunately %s hits matched unformattable documents from %s, an internal error has been logged):</p>'%(len(errors),dp)
427                        status, message=mailHandler([g.metadataMaintainer],'DIF errors',
428                                                    str(errors), server = g.mailServer)
429                        if not status:
430                            c.xml+='<p> Actually, not even an internal error has been logged. <br/>'
431                            c.xml+='Internal sending of mail failed with error [%s]</p>'%message
432                   
433                # if we're here, we're ready to display the dif records
434                c.difs = difs
435                session['results'] = h.current_url()
436                session.save()
437               
438                # set up the displayed tabs
439                if len(c.pageTabs)==1: 
440                    c.pageTabs.append(('Results', session['results']))
441                    #c.pageTabs.append(('Selections',
442                     #                  h.url_for(controller='visualise/selectedItems',
443                      #                           action='index')))
444                elif c.pageTabs[1][0]!='Results':
445                        c.pageTabs.insert(1,('Results',session['results']))
446                        selectionsNeeded=1
447                        for tab in c.pageTabs[0]:
448                            if tab == 'Selections':
449                                selectionsNeeded=0
450                        if selectionsNeeded:
451                            c.pageTabs.append(('Selections',
452                                       h.url_for(controller='visualise/selectedItems',
453                                                 action='index')))
454                           
455                   
456            except ValueError,e:
457                if g.debugModeOn == 'True':
458                    raise ValueError,str(e)
459
460                c.xml='<p> Error retrieving documents for %s hits is [%s]</p>'%(hits,e)
461
462        return render('browse/results')
463       
464    def __advancedPrompt(self, searchConstraints = None):
465        '''
466        This provides the advanced search input page
467        @keyword searchConstraints: a DiscoveryState.constraints object with the
468        search filter details in
469        '''
470        #defaults
471        c.title = bc.DISCOVERY_HOME_TITLE
472        c.helpEmail = bc.DISCOVERY_HELP_EMAIL
473        c.oaiPage = bc.OAI_PROVIDER_PAGE
474        c.bbox='90.0','-180.0','180.0','-90.0'
475        #c.bbox='','','',''
476        c.startDate = ''
477        c.endDate = ''
478        c.textTarget='All'
479        c.searchString=''
480        c.source=['All']
481        c.geoSearchType='overlaps'
482
483        # apply any available constraints
484        if searchConstraints:
485            if searchConstraints['dateRange']:
486                c.startDate = '%s/%s/%s' %searchConstraints['dateRange'][0]
487                c.endDate = '%s/%s/%s' %searchConstraints['dateRange'][1]
488            if searchConstraints['bbox']:
489                c.bbox=searchConstraints['bbox']
490            if searchConstraints['textTarget']:
491                c.textTarget=searchConstraints['textTarget']
492            if searchConstraints['searchString']:
493                c.searchString=searchConstraints['searchString']
494            if searchConstraints['scope']:
495                c.source=searchConstraints['scope']
496            if searchConstraints['geoSearchType']:
497                c.geoSearchType = searchConstraints['geoSearchType']
498               
499        # NB, htmlfill doesn't handle the checked property correctly, so need
500        # to add this explicitly here.
501        if 'source' not in self.inputs:
502            self.inputs['source'] = 'All' # Here is where you make "All" the default search type
503           
504        if 'radioSearchType' not in self.inputs:
505            self.inputs['radioSearchType'] = 'free' # Here is where you make the free text search the default search type
506       
507        return self.savePageAndRender("browse/discovery_search", **self.inputs)
508
509       
510    def __checkBBoxValidity(self, bbox):
511        '''
512        Check the integrity of the bounding box; return any errors found as list
513        @return: list of errors
514        '''
515        errors = []
516       
517        for name, val in [('North', float(bbox[0])), ('South', float(bbox[3]))]:
518            if val > 90.0 or val < -90.:
519                errors.append("%s latitude exceeds valid range - -90 <= x <= 90" %name)
520               
521        for name, val in [('West', float(bbox[1])), ('East', float(bbox[2]))]:
522            if val > 180.0 or val < -180.:
523                errors.append("%s longitude exceeds valid range - -180 <= x <= 180" %name)
524        return errors
525
526           
527    def __checkform(self,expected):
528        '''
529        Simply checks the inputs to make sure the elements in expected are present
530        - NB, this isn't actually checking that a value for these inputs are set, it
531        is just checking the fields are there
532        @return array of missing inputs
533        '''
534        logging.debug("Checking for missing inputs")
535        missingInputs = []
536        for i in expected:
537            if i not in self.inputs:
538                logging.debug(" - found missing input: %s" %i)
539                missingInputs.append(i)
540        logging.debug("Finished checking for missing inputs")
541        return missingInputs
542       
543               
544    def __checkdates(self,dateRange):
545        '''
546        Check input dates for sanity
547        @return: error message, if invalid, None otherwise
548        '''
549        if not ValidDate(dateRange[0])*ValidDate(dateRange[1]):
550            return str(dateRange)
551        elif JulDay(dateRange[0]) >= JulDay(dateRange[1]):
552            return 'second date must be after first date'
553     
554        return None
555   
556    def __sortedDictValues(self, dictionary):
557        '''
558        Sort dictionary of values for ordering
559        '''
560        keys = dictionary.keys()
561        keys.sort()
562       
563        return [dictionary.get, keys]
564
565       
566    def __buildconstraints(self, dateRange, bbox, scope, searchString, geoSearch):
567        '''
568        Build and return a DiscoveryState.constraints object
569        '''
570        return constraints(dateRange=dateRange, bbox=bbox,
571                           scope=scope, searchString=searchString, 
572                           geoSearchType=geoSearch)
573       
574
575    def semantic(self):
576        self.__setup()
577        vs = VS(proxyServer = g.proxyServer)
578       
579       
580        if 'searchString' in self.inputs:
581            try:
582                # NB, the search doesn't work with aggregated info so just
583                # look up both in turn
584                broader = []
585                narrower = []
586                synonyms = []
587                if 'searchString' in self.inputs and self.inputs['searchString']:
588                    [broader, narrower, synonyms] = \
589                        vs.getRelated(self.inputs['searchString'])
590
591                if 'vocabTerm' in self.inputs and self.inputs['vocabTerm']:
592                    [broader1, narrower1, synonyms1] = \
593                        vs.getRelated(self.inputs['vocabTerm'])
594                   
595                    broader = self.__addNewTerms(broader, broader1)
596                    narrower = self.__addNewTerms(narrower, narrower1)
597                    synonyms = self.__addNewTerms(synonyms, synonyms1)
598                   
599                   
600                #get a base string for the links to new searches
601                if 'start' in self.inputs: 
602                    del self.inputs['start']
603                if 'howmany' in self.inputs: 
604                    del self.inputs['howmany']
605                self.inputs['searchString']='###SEARCHSSTRING###'
606                q='%s/discovery?'%g.server
607                for i in self.inputs: q+='%s=%s&'%(i,self.inputs[i])
608                url=q[0:-1]
609                # and now build the links
610                c.narrower=[]
611                c.broader=[]
612                c.synonyms=[]
613                for i in narrower:
614                    c.narrower.append((i,url.replace('###SEARCHSSTRING###',i)))
615                for i in broader:
616                    c.broader.append((i,url.replace('###SEARCHSSTRING###',i)))
617                for i in synonyms:
618                    c.synonyms.append((i,url.replace('###SEARCHSSTRING###',i)))
619                if c.narrower!=[] or c.broader!=[] or c.synonyms!=[]: c.semAvailable=1
620            except IOError,e:
621                c.semAvailable=0
622                c.semError=' (No valid reply from vocabulary service)'
623                #This should go in a log file ...
624                print 'ERROR: Vocabulary Service: %s (for search [%s])'%(str(e),self.inputs['searchString'])
625        else:
626            broader,narrower,synonyms=[],[],[]
627            c.semAvailable=0
628            c.semError='.'
629       
630        return render('browse/semantic',fragment=True)
631
632
633    def __addNewTerms(self, toList, fromList):
634        '''
635        Add any terms in list2 not in list1 to list1 - and then return this list
636        @param toList: list to add terms to
637        @param fromList: list to add terms from
638        '''
639        for data in fromList:
640            if data not in toList:
641                toList.append(data)
642               
643        return toList
644   
645    def __displayBrowseSearchResults(self, searchClient):
646        '''
647        Provides the search results for Browse and NumSim content
648        @param searchClient: search client adhering to the ndg.common.clients.interfacesearchclient
649        interface - which has just ran a search
650        '''
651        c.results = searchClient.results
652        c.searchTarget = self.inputs['searchTarget']
653        textTarget = self.inputs['textTarget']
654
655        # check if we've done a search against atoms - NB, this should be the
656        # default eventually - so we can remove all the alternative options
657        isAtom = False
658        if textTarget == SearchClient.ATOM_TARGET:
659            isAtom = True
660       
661        for r in c.results:
662            id = r.id
663                # cope with atom docs
664            if isAtom:
665                r.link = r.href
666            else:
667                n=ndgObject(id,config=self.cf)
668                r.link={'Browse':n.BURL,'NumSim':n.URL}[c.searchTarget]
669
670        # filter atom docs according to publication state
671        if isAtom:
672            c.searchTerm = " - for search term, '%s'" %self.inputs['searchString']
673            if not g.atomEditorEnabled:
674                c.results = self.__filterAtomResults(c.results)
675
676            if c.results:
677                c.searchTerm += ' [%s results found]' %len(c.results)
678               
679               
680            html = render('genshi', 'browse/short_atom_results')
681            # make sure the edit links point to the editor, not the browse service
682            html = html.replace(VTD.BROWSE_SERVER_URL + '/editAtom', g.server + '/editAtom')
683            return html
684        else:
685            return render('browse/short_results')
686
687
688    def __filterAtomResults(self, results):
689        '''
690        Given a set of atom docs search results, filter these to only return docs in the
691        'published' or 'Published' state
692        @param results: list of results as returned by SearchClient
693        @return filteredResults: list of results with only published data included
694        '''
695        logging.debug("Filtering results to remove non-published data")
696        filteredResults = []
697        for result in results:
698            if result.collection.find('ublished') == -1:
699                logging.debug("- found non-published doc - ignoring")
700                continue
701            filteredResults.append(result)
702        logging.debug("- returning filtered results")
703        return filteredResults
704
705           
706    def clearSession(self):
707        '''
708        Clear out all session variables - to help when these change in development
709        '''
710        session.clear()
711        session.save()           
712     
Note: See TracBrowser for help on using the repository browser.