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

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

Adds client IP address to xml msg 2 send to api..

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