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

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

Additions to make default search all and generate sensible list of orderby fields

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