source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/discovery.py @ 2763

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/discovery.py@2763
Revision 2763, 11.5 KB checked in by lawrence, 12 years ago (diff)

One missing template, and one minor bug fix in the
pass off to semantic search.

Line 
1from ows_server.lib.base import *
2from paste.request import parse_querystring
3from ows_server.lib.Date import *
4from ows_server.templates import DiscoveryTemplate
5from ows_server.models import ndgSearch as NS
6from ows_server.models.DIF import DIF
7from ows_server.templates.renderDiscoverySet import renderDiscoverySet
8from ows_server.models.DiscoveryState import DiscoveryState,constraints
9from ows_server.models.ndgObject import ndgObject
10from ows_server.models.Utilities import myConfig
11from ows_server.lib.mailer import mailHandler
12
13
14class DiscoveryController(BaseController):
15    ''' Provides the pylons controller for NDG discovery '''
16   
17    def __setup(self):
18        ''' Common setup for controller methods '''
19        self.cf=request.environ['ndgConfig']
20        self.inputs=dict(parse_querystring(request.environ))
21        self.message=''
22   
23    def index(self):
24       
25        self.__setup()
26        # parse the query string and hand off to a discovery engine
27        if self.inputs=={} or 'ClearForm' in self.inputs: return self.__advancedPrompt()
28       
29        #the following need to be defined
30        continuations={'start':1,'howmany':10}
31        for i in continuations:
32            if i not in self.inputs: self.inputs[i]=continuations[i]
33           
34           
35        # the simplest query we might get is a text search, in which case
36        # the inputs should be start, howmany and searchString (although
37        # maybe not in that order. The next simplest is one with
38        # a specified textTarget, after that we need all the inputs.
39       
40        if 'searchString' in self.inputs and 'textTarget' not in self.inputs:
41            # it's a simple text search
42            self.inputs['textTarget']='All'
43           
44        # the next simplest is one that includes texttarget as well ...
45        expected=['searchString','textTarget','start','howmany']
46        self.__checkform(expected)
47   
48        if self.message!='':
49            c.xml=self.message
50            return render_response('content')
51       
52        if len(self.inputs)==4:
53           
54            # now we add the defaults ...
55            # this is kind of historical ...
56            bbox=None
57            dateRange=None
58            scope=None
59       
60        else:
61       
62            #check advanced search options
63            expected=['startDateDay','startDateMon','startDateYear',
64                            'endDateDay','endDateMon','endDateYear',
65                            'bboxN','bboxE','bboxS','bboxW','searchString','textTarget'] 
66            self.__checkform(expected)
67            if self.message!='': 
68                c.xml=self.message
69                return render_response('content')
70           
71            # ------------- Handle scope from radio button on form -------
72            if 'source' in self.inputs:
73                # the WSDL expects a list, we're just providing one ... via a radio ...
74                scope=[self.inputs['source']]
75                if scope==['All']: scope=None
76            else:
77                scope=None
78           
79            # ------------- Handle Location Bounding --------
80            # default form has a global bounding box
81            bbox=[self.inputs['bboxN'],self.inputs['bboxS'],self.inputs['bboxW'],self.inputs['bboxE']]
82            self.__checkbox(bbox)
83            if self.message!='': 
84                c.xml=self.message
85                return render_response('content')
86   
87            # ------------- Handle Date Ranges ---------------
88            try:
89                dateRange=[(self.inputs['startDateDay'],self.inputs['startDateMon'],self.inputs['startDateYear']),
90                            (self.inputs['endDateDay'],self.inputs['endDateMon'],self.inputs['endDateYear'])]
91                #default form has blanks, in which case we don't want to check for date range
92                if dateRange<>[("","",""),("","","")]:
93                    self.__checkdates(dateRange)
94                else: dateRange=None           
95            except:
96                self.message='Invalid date provided'
97            if self.message!='': 
98                c.xml=self.message
99                return render_response('content')
100               
101               
102        if 'constrained' in self.inputs: 
103            con=self.__buildconstraints(dateRange,bbox,scope,self.inputs['searchString'])
104            return self.__advancedPrompt(searchConstraints=con)
105        else:
106        # ------------- ok, now go do the search -----------
107           response=self.doText(self.inputs['searchString'],self.inputs['textTarget'],
108                self.inputs['start'],self.inputs['howmany'],scope=scope,dateRange=dateRange,bbox=bbox)
109           return response
110
111    def doText(self,searchString,textTarget,start,howmany,scope=None,dateRange=None,bbox=None):
112       
113        ''' Carry out a text search for <searchString>
114        in the <textTarget> where the accepted text target values are controlled
115        by the DiscoveryTemplate GUI, and are: All, Authors, Parameters '''
116       
117        start,howmany=int(start),int(howmany)  # url arguments need conversion ...
118       
119        ws=NS.ndgSearch(logger=logger)
120        documents=ws.search(searchString,start=start,howmany=howmany,target=textTarget,
121                            scope=scope,dateRange=dateRange,bbox=bbox)
122        if ws.error !=None:
123            m=''
124            for i in ws.error:m+='<p>%s</p>'%i
125            c.xml=m
126            return render_response('content')
127       
128        #build constraints info for report
129        searchConstraints=self.__buildconstraints(dateRange,bbox,scope,searchString)
130       
131        hits=ws.hits
132        id=ws.serverSessionID
133       
134        if hits<howmany:howmany=hits
135        state=DiscoveryState(id,searchString,request.environ,hits,searchConstraints,start,howmany)
136       
137        if hits==0: 
138            c.xml='<p>No records found [%s]</p>>'%state.constraints
139            return render_response('content')
140       
141        try:
142            results=ws.getLabelledDocs(format='DIF')
143            difs=[]
144            errors=[]
145            for result in results: 
146                obj=ndgObject(result[0])
147                obj.setConfig(self.cf)
148                try:
149                    difs.append(DIF(result[1],ndgObj=obj))
150                except ValueError,e:
151                    errors.append((result[0],str(e)))
152            if results==[]:
153                c.xml='<p> No results for "%s"!</p>'%searchString
154                return render_response('content')
155            elif difs==[]:
156                c.xml='<p>No usable results for "%s"!</p>'%searchString
157                return render_response('content')
158            else:
159                if errors<>[]:
160                    c.xml='<p>Search results for "%s"'%searchString
161                    dp=[]
162                    for e in errors:
163                        n=ndgObject(e[0])
164                        if n.repository not in dp: dp.append(n.repository)
165                    if len(dp)<>1: 
166                        dp='[Various Data Providers]'
167                    else:
168                        dp='[%s]'%dp[0] 
169                    c.xml+=' (unfortunately %s hits matched unformattable documents from %s, an internal error has been logged):</p>'%(len(errors),dp)
170                    status,message=mailHandler(['b.n.lawrence@rl.ac.uk'],'DIF errors',str(errors),
171                                    server=self.cf.get('DEFAULT',mailsever))
172                    if not status:
173                        c.xml+='<p> Actually, not even an internal error has been logged. <br/>'
174                        c.xml+='Internal sending of mail failed with error [%s]</p>'%message
175                    return render_response('content')
176                if 0:
177                    c.xml=renderDiscoverySet(difs,state,self.cf)
178                    f=file('debug-dif.xml','w')
179                    f.write(c.xml)
180                    f.close()
181                    return render_response('content')
182                else:
183                    c.state=state
184                    c.difs=difs
185                    if 'searchString' in self.inputs:
186                        c.querystring='searchString=%s&textTarget=%s'%(self.inputs['searchString'],self.inputs['textTarget'])
187                    else:
188                        c.querystring=''
189                    return render_response('results')
190               
191        except ValueError,e:
192            if debug: 
193                raise ValueError,str(e)
194            else:
195                c.xml='<p> Error retrieving documents for %s hits is [%s]</p>'%(hits,e)
196                return render_response('content')
197                               
198        return
199    def __advancedPrompt(self,searchConstraints=None):
200        ''' This provides the advanced search input page '''
201        try:
202            discoveryURL=self.cf.get('SEARCH','discoveryURL')
203            advancedURL=self.cf.get('SEARCH','advancedURL')
204        except:
205            return 'Error, invalid configuration for search interface'
206        #defaults
207        c.bbox='+90.0','-180.0','+180.0','-90.0'
208        c.startDateDay,c.startDateMon,c.startDateYear='','',''
209        c.endDateDay,c.endDateMon,c.endDateYear='','',''
210        c.textTarget='All'
211        c.searchString=''
212        c.source=['All']
213        #constraints
214        if searchConstraints is not None:
215            if searchConstraints['dateRange'] is not None:
216                c.startDateDay,c.startDateMon,c.startDateYear=searchConstraints['dateRange'][0]
217                c.endDateDay,c.endDateMon,c.endDateYear=searchConstraints['dateRange'][1]
218            if searchConstraints['bbox'] is not None:
219                bboxN,bboxW,bboxE,bboxS=searchConstraints['bbox']
220            if searchConstraints['textTarget'] is not None:
221                c.textTarget=searchConstraints['textTarget']
222            if searchConstraints['searchString'] is not None:
223                c.searchString=searchConstraints['searchString']
224            if searchConstraints['scope'] is not None:
225                c.source=searchConstraintss['scope']
226               
227        return render_response('advanced')
228       
229    def __checkbox(self,bbox):
230        if float(bbox[0])>90.0 or float(bbox[1])<-90. or float(bbox[2])<-180. or float(bbox[3])>180.:
231            self.message='Invalid bounding box dimensions entered (limits 90,-90,-180,180)'
232           
233    def __checkform(self,expected):
234        ''' Simply checks the inputs to make sure the elements in expected are present '''
235        message="An incomplete NDG search form was received: "
236        for i in expected:
237            if i not in self.inputs: 
238                self.message=message+i
239        if self.message!='':self.message+='[%s]'%self.inputs
240               
241    def __checkdates(self,dateRange):
242        ''' Check input dates for sanity '''
243        print 'dr',dateRange
244        if not ValidDate(dateRange[0])*ValidDate(dateRange[1]):
245            self.message='Input dates are not valid [%s]'%dateRange
246        elif JulDay(dateRange[0])>=JulDay(dateRange[1]):
247            self.message='Second date must be after first date'
248       
249    def __buildconstraints(self,dateRange,bbox,scope,searchString):
250        ''' Just build a constraint string '''
251        return constraints(dateRange=dateRange,bbox=bbox,scope=scope,searchString=searchString)
252       
253    #def oneLineSearch(self):
254    #    try:
255    #        discoveryURL=self.cf.get('SEARCH','discoveryURL')
256    #        oneLiner=DiscoveryTemplate.oneLiner
257    #    except:
258    #        return 'Error, invalid configuration for search interface'
259    #    return DiscoveryTemplate.searchTextOneLine%locals() 
260   
261    def semantic(self):
262        c.constraints=request.environ['QUERY_STRING']
263        return render_response('semantic',fragment=True)
Note: See TracBrowser for help on using the repository browser.