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

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

Got rid of selections tab for now

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'
503       
504        return self.savePageAndRender("browse/discovery_search", **self.inputs)
505
506       
507    def __checkBBoxValidity(self, bbox):
508        '''
509        Check the integrity of the bounding box; return any errors found as list
510        @return: list of errors
511        '''
512        errors = []
513       
514        for name, val in [('North', float(bbox[0])), ('South', float(bbox[3]))]:
515            if val > 90.0 or val < -90.:
516                errors.append("%s latitude exceeds valid range - -90 <= x <= 90" %name)
517               
518        for name, val in [('West', float(bbox[1])), ('East', float(bbox[2]))]:
519            if val > 180.0 or val < -180.:
520                errors.append("%s longitude exceeds valid range - -180 <= x <= 180" %name)
521        return errors
522
523           
524    def __checkform(self,expected):
525        '''
526        Simply checks the inputs to make sure the elements in expected are present
527        - NB, this isn't actually checking that a value for these inputs are set, it
528        is just checking the fields are there
529        @return array of missing inputs
530        '''
531        logging.debug("Checking for missing inputs")
532        missingInputs = []
533        for i in expected:
534            if i not in self.inputs:
535                logging.debug(" - found missing input: %s" %i)
536                missingInputs.append(i)
537        logging.debug("Finished checking for missing inputs")
538        return missingInputs
539       
540               
541    def __checkdates(self,dateRange):
542        '''
543        Check input dates for sanity
544        @return: error message, if invalid, None otherwise
545        '''
546        if not ValidDate(dateRange[0])*ValidDate(dateRange[1]):
547            return str(dateRange)
548        elif JulDay(dateRange[0]) >= JulDay(dateRange[1]):
549            return 'second date must be after first date'
550     
551        return None
552   
553    def __sortedDictValues(self, dictionary):
554        '''
555        Sort dictionary of values for ordering
556        '''
557        keys = dictionary.keys()
558        keys.sort()
559       
560        return [dictionary.get, keys]
561
562       
563    def __buildconstraints(self, dateRange, bbox, scope, searchString, geoSearch):
564        '''
565        Build and return a DiscoveryState.constraints object
566        '''
567        return constraints(dateRange=dateRange, bbox=bbox,
568                           scope=scope, searchString=searchString, 
569                           geoSearchType=geoSearch)
570       
571
572    def semantic(self):
573        self.__setup()
574        vs = VS(proxyServer = g.proxyServer)
575       
576       
577        if 'searchString' in self.inputs:
578            try:
579                # NB, the search doesn't work with aggregated info so just
580                # look up both in turn
581                broader = []
582                narrower = []
583                synonyms = []
584                if 'searchString' in self.inputs and self.inputs['searchString']:
585                    [broader, narrower, synonyms] = \
586                        vs.getRelated(self.inputs['searchString'])
587
588                if 'vocabTerm' in self.inputs and self.inputs['vocabTerm']:
589                    [broader1, narrower1, synonyms1] = \
590                        vs.getRelated(self.inputs['vocabTerm'])
591                   
592                    broader = self.__addNewTerms(broader, broader1)
593                    narrower = self.__addNewTerms(narrower, narrower1)
594                    synonyms = self.__addNewTerms(synonyms, synonyms1)
595                   
596                   
597                #get a base string for the links to new searches
598                if 'start' in self.inputs: 
599                    del self.inputs['start']
600                if 'howmany' in self.inputs: 
601                    del self.inputs['howmany']
602                self.inputs['searchString']='###SEARCHSSTRING###'
603                q='%s/discovery?'%g.server
604                for i in self.inputs: q+='%s=%s&'%(i,self.inputs[i])
605                url=q[0:-1]
606                # and now build the links
607                c.narrower=[]
608                c.broader=[]
609                c.synonyms=[]
610                for i in narrower:
611                    c.narrower.append((i,url.replace('###SEARCHSSTRING###',i)))
612                for i in broader:
613                    c.broader.append((i,url.replace('###SEARCHSSTRING###',i)))
614                for i in synonyms:
615                    c.synonyms.append((i,url.replace('###SEARCHSSTRING###',i)))
616                if c.narrower!=[] or c.broader!=[] or c.synonyms!=[]: c.semAvailable=1
617            except IOError,e:
618                c.semAvailable=0
619                c.semError=' (No valid reply from vocabulary service)'
620                #This should go in a log file ...
621                print 'ERROR: Vocabulary Service: %s (for search [%s])'%(str(e),self.inputs['searchString'])
622        else:
623            broader,narrower,synonyms=[],[],[]
624            c.semAvailable=0
625            c.semError='.'
626       
627        return render('browse/semantic',fragment=True)
628
629
630    def __addNewTerms(self, toList, fromList):
631        '''
632        Add any terms in list2 not in list1 to list1 - and then return this list
633        @param toList: list to add terms to
634        @param fromList: list to add terms from
635        '''
636        for data in fromList:
637            if data not in toList:
638                toList.append(data)
639               
640        return toList
641   
642    def __displayBrowseSearchResults(self, searchClient):
643        '''
644        Provides the search results for Browse and NumSim content
645        @param searchClient: search client adhering to the ndg.common.clients.interfacesearchclient
646        interface - which has just ran a search
647        '''
648        c.results = searchClient.results
649        c.searchTarget = self.inputs['searchTarget']
650        textTarget = self.inputs['textTarget']
651
652        # check if we've done a search against atoms - NB, this should be the
653        # default eventually - so we can remove all the alternative options
654        isAtom = False
655        if textTarget == SearchClient.ATOM_TARGET:
656            isAtom = True
657       
658        for r in c.results:
659            id = r.id
660                # cope with atom docs
661            if isAtom:
662                r.link = r.href
663            else:
664                n=ndgObject(id,config=self.cf)
665                r.link={'Browse':n.BURL,'NumSim':n.URL}[c.searchTarget]
666
667        # filter atom docs according to publication state
668        if isAtom:
669            c.searchTerm = " - for search term, '%s'" %self.inputs['searchString']
670            if not g.atomEditorEnabled:
671                c.results = self.__filterAtomResults(c.results)
672
673            if c.results:
674                c.searchTerm += ' [%s results found]' %len(c.results)
675               
676               
677            html = render('genshi', 'browse/short_atom_results')
678            # make sure the edit links point to the editor, not the browse service
679            html = html.replace(VTD.BROWSE_SERVER_URL + '/editAtom', g.server + '/editAtom')
680            return html
681        else:
682            return render('browse/short_results')
683
684
685    def __filterAtomResults(self, results):
686        '''
687        Given a set of atom docs search results, filter these to only return docs in the
688        'published' or 'Published' state
689        @param results: list of results as returned by SearchClient
690        @return filteredResults: list of results with only published data included
691        '''
692        logging.debug("Filtering results to remove non-published data")
693        filteredResults = []
694        for result in results:
695            if result.collection.find('ublished') == -1:
696                logging.debug("- found non-published doc - ignoring")
697                continue
698            filteredResults.append(result)
699        logging.debug("- returning filtered results")
700        return filteredResults
701
702           
703    def clearSession(self):
704        '''
705        Clear out all session variables - to help when these change in development
706        '''
707        session.clear()
708        session.save()           
709     
Note: See TracBrowser for help on using the repository browser.