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

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

Updates to allow proper paging as per num of search results and ordering of orderby without letter prefix

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        print "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv  "
368       
369        hits = searchClient.hits
370        # NB, this is used in the semantic search function of results.kid and short_results.kid
371        c.querystring = request.environ['QUERY_STRING']
372        c.altSearchURL = '%s?%s'%(h.url_for(action='semantic'),
373                                  request.environ['QUERY_STRING'])
374
375        difs = []
376        errors = []
377
378        if hits == 0 and ds.constraintsInstance['textTarget'] != SearchClient.ATOM_TARGET:
379            outMessage = 'No records found for "%s"[constraints: %s]' \
380                %(ds.searchString, ds.constraints)
381            logging.info(outMessage) 
382            c.xml='<p>' + outMessage + '</p>'
383
384        else:
385            try:
386                # display browse search results differently
387                if self.inputs['searchTarget'] != 'Discovery':
388                    return self.__displayBrowseSearchResults(searchClient)
389   
390                # now actually retrieve the search records
391               
392                results = searchClient.getLabelledDocs(format='DIF')
393                               
394               
395                if not results:
396                    c.xml='<p>No results for "%s"!</p>'%ds.searchString
397                   
398                else:
399                    for result in results:
400                       
401                        obj=ndgObject(result[0], config = self.cf)
402                        try:
403                           
404                            difs.append(DIF(result[1],ndgObj=obj))
405                           
406                        except ValueError,e:
407                           
408                            errors.append((result[0], str(e)))
409       
410                    if not difs:
411                        c.xml='<p>No usable results for "%s"!</p>'%ds.searchString
412                   
413                    elif errors:
414                        c.xml='<p>Search results for "%s"'%ds.searchString
415                        dp=[]
416                        for e in errors:
417                            n=ndgObject(e[0])
418                            if n.repository not in dp: 
419                                dp.append(n.repository)
420                        if len(dp)<>1: 
421                            dp='[Various Data Providers]'
422                        else:
423                            dp='[%s]'%dp[0] 
424                           
425                        c.xml+=' (unfortunately %s hits matched unformattable documents from %s, an internal error has been logged):</p>'%(len(errors),dp)
426                        status, message=mailHandler([g.metadataMaintainer],'DIF errors',
427                                                    str(errors), server = g.mailServer)
428                        if not status:
429                            c.xml+='<p> Actually, not even an internal error has been logged. <br/>'
430                            c.xml+='Internal sending of mail failed with error [%s]</p>'%message
431                   
432                # if we're here, we're ready to display the dif records
433                c.difs = difs
434                session['results'] = h.current_url()
435                session.save()
436               
437                # set up the displayed tabs
438                if len(c.pageTabs)==1: 
439                    c.pageTabs.append(('Results', session['results']))
440                    c.pageTabs.append(('Selections',
441                                       h.url_for(controller='visualise/selectedItems',
442                                                 action='index')))
443                elif c.pageTabs[1][0]!='Results':
444                        c.pageTabs.insert(1,('Results',session['results']))
445                        selectionsNeeded=1
446                        for tab in c.pageTabs[0]:
447                            if tab == 'Selections':
448                                selectionsNeeded=0
449                        if selectionsNeeded:
450                            c.pageTabs.append(('Selections',
451                                       h.url_for(controller='visualise/selectedItems',
452                                                 action='index')))
453                           
454                   
455            except ValueError,e:
456                if g.debugModeOn == 'True':
457                    raise ValueError,str(e)
458
459                c.xml='<p> Error retrieving documents for %s hits is [%s]</p>'%(hits,e)
460
461        return render('browse/results')
462       
463    def __advancedPrompt(self, searchConstraints = None):
464        '''
465        This provides the advanced search input page
466        @keyword searchConstraints: a DiscoveryState.constraints object with the
467        search filter details in
468        '''
469        #defaults
470        c.title = bc.DISCOVERY_HOME_TITLE
471        c.helpEmail = bc.DISCOVERY_HELP_EMAIL
472        c.oaiPage = bc.OAI_PROVIDER_PAGE
473        c.bbox='90.0','-180.0','180.0','-90.0'
474        #c.bbox='','','',''
475        c.startDate = ''
476        c.endDate = ''
477        c.textTarget='All'
478        c.searchString=''
479        c.source=['All']
480        c.geoSearchType='overlaps'
481
482        # apply any available constraints
483        if searchConstraints:
484            if searchConstraints['dateRange']:
485                c.startDate = '%s/%s/%s' %searchConstraints['dateRange'][0]
486                c.endDate = '%s/%s/%s' %searchConstraints['dateRange'][1]
487            if searchConstraints['bbox']:
488                c.bbox=searchConstraints['bbox']
489            if searchConstraints['textTarget']:
490                c.textTarget=searchConstraints['textTarget']
491            if searchConstraints['searchString']:
492                c.searchString=searchConstraints['searchString']
493            if searchConstraints['scope']:
494                c.source=searchConstraints['scope']
495            if searchConstraints['geoSearchType']:
496                c.geoSearchType = searchConstraints['geoSearchType']
497               
498        # NB, htmlfill doesn't handle the checked property correctly, so need
499        # to add this explicitly here
500        if 'source' not in self.inputs:
501            self.inputs['source'] = 'All'
502       
503        return self.savePageAndRender("browse/discovery_search", **self.inputs)
504
505       
506    def __checkBBoxValidity(self, bbox):
507        '''
508        Check the integrity of the bounding box; return any errors found as list
509        @return: list of errors
510        '''
511        errors = []
512       
513        for name, val in [('North', float(bbox[0])), ('South', float(bbox[3]))]:
514            if val > 90.0 or val < -90.:
515                errors.append("%s latitude exceeds valid range - -90 <= x <= 90" %name)
516               
517        for name, val in [('West', float(bbox[1])), ('East', float(bbox[2]))]:
518            if val > 180.0 or val < -180.:
519                errors.append("%s longitude exceeds valid range - -180 <= x <= 180" %name)
520        return errors
521
522           
523    def __checkform(self,expected):
524        '''
525        Simply checks the inputs to make sure the elements in expected are present
526        - NB, this isn't actually checking that a value for these inputs are set, it
527        is just checking the fields are there
528        @return array of missing inputs
529        '''
530        logging.debug("Checking for missing inputs")
531        missingInputs = []
532        for i in expected:
533            if i not in self.inputs:
534                logging.debug(" - found missing input: %s" %i)
535                missingInputs.append(i)
536        logging.debug("Finished checking for missing inputs")
537        return missingInputs
538       
539               
540    def __checkdates(self,dateRange):
541        '''
542        Check input dates for sanity
543        @return: error message, if invalid, None otherwise
544        '''
545        if not ValidDate(dateRange[0])*ValidDate(dateRange[1]):
546            return str(dateRange)
547        elif JulDay(dateRange[0]) >= JulDay(dateRange[1]):
548            return 'second date must be after first date'
549     
550        return None
551   
552    def __sortedDictValues(self, dictionary):
553        '''
554        Sort dictionary of values for ordering
555        '''
556        keys = dictionary.keys()
557        keys.sort()
558       
559        return [dictionary.get, keys]
560
561       
562    def __buildconstraints(self, dateRange, bbox, scope, searchString, geoSearch):
563        '''
564        Build and return a DiscoveryState.constraints object
565        '''
566        return constraints(dateRange=dateRange, bbox=bbox,
567                           scope=scope, searchString=searchString, 
568                           geoSearchType=geoSearch)
569       
570
571    def semantic(self):
572        self.__setup()
573        vs = VS(proxyServer = g.proxyServer)
574        if 'searchString' in self.inputs:
575            try:
576                # NB, the search doesn't work with aggregated info so just
577                # look up both in turn
578                broader = []
579                narrower = []
580                synonyms = []
581                if 'searchString' in self.inputs and self.inputs['searchString']:
582                    [broader, narrower, synonyms] = \
583                        vs.getRelated(self.inputs['searchString'])
584
585                if 'vocabTerm' in self.inputs and self.inputs['vocabTerm']:
586                    [broader1, narrower1, synonyms1] = \
587                        vs.getRelated(self.inputs['vocabTerm'])
588                   
589                    broader = self.__addNewTerms(broader, broader1)
590                    narrower = self.__addNewTerms(narrower, narrower1)
591                    synonyms = self.__addNewTerms(synonyms, synonyms1)
592                   
593                   
594                #get a base string for the links to new searches
595                if 'start' in self.inputs: 
596                    del self.inputs['start']
597                if 'howmany' in self.inputs: 
598                    del self.inputs['howmany']
599                self.inputs['searchString']='###SEARCHSSTRING###'
600                q='%s/discovery?'%g.server
601                for i in self.inputs: q+='%s=%s&'%(i,self.inputs[i])
602                url=q[0:-1]
603                # and now build the links
604                c.narrower=[]
605                c.broader=[]
606                c.synonyms=[]
607                for i in narrower:
608                    c.narrower.append((i,url.replace('###SEARCHSSTRING###',i)))
609                for i in broader:
610                    c.broader.append((i,url.replace('###SEARCHSSTRING###',i)))
611                for i in synonyms:
612                    c.synonyms.append((i,url.replace('###SEARCHSSTRING###',i)))
613                if c.narrower!=[] or c.broader!=[] or c.synonyms!=[]: c.semAvailable=1
614            except IOError,e:
615                c.semAvailable=0
616                c.semError=' (No valid reply from vocabulary service)'
617                #This should go in a log file ...
618                print 'ERROR: Vocabulary Service: %s (for search [%s])'%(str(e),self.inputs['searchString'])
619        else:
620            broader,narrower,synonyms=[],[],[]
621            c.semAvailable=0
622            c.semError='.'
623       
624        return render('browse/semantic',fragment=True)
625
626
627    def __addNewTerms(self, toList, fromList):
628        '''
629        Add any terms in list2 not in list1 to list1 - and then return this list
630        @param toList: list to add terms to
631        @param fromList: list to add terms from
632        '''
633        for data in fromList:
634            if data not in toList:
635                toList.append(data)
636               
637        return toList
638   
639    def __displayBrowseSearchResults(self, searchClient):
640        '''
641        Provides the search results for Browse and NumSim content
642        @param searchClient: search client adhering to the ndg.common.clients.interfacesearchclient
643        interface - which has just ran a search
644        '''
645        c.results = searchClient.results
646        c.searchTarget = self.inputs['searchTarget']
647        textTarget = self.inputs['textTarget']
648
649        # check if we've done a search against atoms - NB, this should be the
650        # default eventually - so we can remove all the alternative options
651        isAtom = False
652        if textTarget == SearchClient.ATOM_TARGET:
653            isAtom = True
654       
655        for r in c.results:
656            id = r.id
657                # cope with atom docs
658            if isAtom:
659                r.link = r.href
660            else:
661                n=ndgObject(id,config=self.cf)
662                r.link={'Browse':n.BURL,'NumSim':n.URL}[c.searchTarget]
663
664        # filter atom docs according to publication state
665        if isAtom:
666            c.searchTerm = " - for search term, '%s'" %self.inputs['searchString']
667            if not g.atomEditorEnabled:
668                c.results = self.__filterAtomResults(c.results)
669
670            if c.results:
671                c.searchTerm += ' [%s results found]' %len(c.results)
672               
673               
674            html = render('genshi', 'browse/short_atom_results')
675            # make sure the edit links point to the editor, not the browse service
676            html = html.replace(VTD.BROWSE_SERVER_URL + '/editAtom', g.server + '/editAtom')
677            return html
678        else:
679            return render('browse/short_results')
680
681
682    def __filterAtomResults(self, results):
683        '''
684        Given a set of atom docs search results, filter these to only return docs in the
685        'published' or 'Published' state
686        @param results: list of results as returned by SearchClient
687        @return filteredResults: list of results with only published data included
688        '''
689        logging.debug("Filtering results to remove non-published data")
690        filteredResults = []
691        for result in results:
692            if result.collection.find('ublished') == -1:
693                logging.debug("- found non-published doc - ignoring")
694                continue
695            filteredResults.append(result)
696        logging.debug("- returning filtered results")
697        return filteredResults
698
699           
700    def clearSession(self):
701        '''
702        Clear out all session variables - to help when these change in development
703        '''
704        session.clear()
705        session.save()           
706     
Note: See TracBrowser for help on using the repository browser.