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

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

Woops, bug fix for a catastrophic failure ...

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, NB, internal to this routine we use bbox=[N,W,E,S], not [W,S,E,N]!
81            bbox=[self.inputs['bboxN'],self.inputs['bboxW'],self.inputs['bboxE'],self.inputs['bboxS']]
82           
83            self.__checkbox(bbox)
84            if self.message!='': 
85                c.xml=self.message
86                return render_response('content')
87   
88            # ------------- Handle Date Ranges ---------------
89            try:
90                dateRange=[(self.inputs['startDateDay'],self.inputs['startDateMon'],self.inputs['startDateYear']),
91                            (self.inputs['endDateDay'],self.inputs['endDateMon'],self.inputs['endDateYear'])]
92                #default form has blanks, in which case we don't want to check for date range
93                if dateRange<>[("","",""),("","","")]:
94                    self.__checkdates(dateRange)
95                else: dateRange=None           
96            except:
97                self.message='Invalid date provided'
98            if self.message!='': 
99                c.xml=self.message
100                return render_response('content')
101               
102               
103        if 'constrained' in self.inputs: 
104            con=self.__buildconstraints(dateRange,bbox,scope,self.inputs['searchString'])
105            return self.__advancedPrompt(searchConstraints=con)
106        else:
107        # ------------- ok, now go do the search -----------
108           response=self.doText(self.inputs['searchString'],self.inputs['textTarget'],
109                self.inputs['start'],self.inputs['howmany'],scope=scope,dateRange=dateRange,bbox=bbox)
110           return response
111
112    def doText(self,searchString,textTarget,start,howmany,scope=None,dateRange=None,bbox=None):
113       
114        ''' Carry out a text search for <searchString>
115        in the <textTarget> where the accepted text target values are controlled
116        by the DiscoveryTemplate GUI, and are: All, Authors, Parameters '''
117       
118        start,howmany=int(start),int(howmany)  # url arguments need conversion ...
119       
120        ws=NS.ndgSearch(logger=logger)
121        documents=ws.search(searchString,start=start,howmany=howmany,target=textTarget,
122                            scope=scope,dateRange=dateRange,bbox=bbox)
123        if ws.error !=None:
124            m=''
125            for i in ws.error:m+='<p>%s</p>'%i
126            c.xml=m
127            return render_response('content')
128       
129        #build constraints info for report
130        searchConstraints=self.__buildconstraints(dateRange,bbox,scope,searchString)
131       
132        hits=ws.hits
133        id=ws.serverSessionID
134       
135        if hits<howmany:howmany=hits
136        state=DiscoveryState(id,searchString,request.environ,hits,searchConstraints,start,howmany)
137       
138        if hits==0: 
139            c.xml='<p>No records found [%s]</p>'%state.constraints
140            return render_response('content')
141       
142        try:
143            results=ws.getLabelledDocs(format='DIF')
144            difs=[]
145            errors=[]
146            for result in results: 
147                obj=ndgObject(result[0])
148                obj.setConfig(self.cf)
149                try:
150                    difs.append(DIF(result[1],ndgObj=obj))
151                except ValueError,e:
152                    errors.append((result[0],str(e)))
153            if results==[]:
154                c.xml='<p> No results for "%s"!</p>'%searchString
155                return render_response('content')
156            elif difs==[]:
157                c.xml='<p>No usable results for "%s"!</p>'%searchString
158                return render_response('content')
159            else:
160                if errors<>[]:
161                    c.xml='<p>Search results for "%s"'%searchString
162                    dp=[]
163                    for e in errors:
164                        n=ndgObject(e[0])
165                        if n.repository not in dp: dp.append(n.repository)
166                    if len(dp)<>1: 
167                        dp='[Various Data Providers]'
168                    else:
169                        dp='[%s]'%dp[0] 
170                    c.xml+=' (unfortunately %s hits matched unformattable documents from %s, an internal error has been logged):</p>'%(len(errors),dp)
171                    status,message=mailHandler(['b.n.lawrence@rl.ac.uk'],'DIF errors',str(errors),
172                                    server=self.cf.get('DEFAULT','mailserver'))
173                    if not status:
174                        c.xml+='<p> Actually, not even an internal error has been logged. <br/>'
175                        c.xml+='Internal sending of mail failed with error [%s]</p>'%message
176                    return render_response('content')
177                if 0:
178                    c.xml=renderDiscoverySet(difs,state,self.cf)
179                    f=file('debug-dif.xml','w')
180                    f.write(c.xml)
181                    f.close()
182                    return render_response('content')
183                else:
184                    c.state=state
185                    c.difs=difs
186                    if 'searchString' in self.inputs:
187                        c.querystring='searchString=%s&textTarget=%s'%(self.inputs['searchString'],self.inputs['textTarget'])
188                    else:
189                        c.querystring=''
190                    session['results']=h.current_url()
191                    session.save()
192                    if len(c.pageTabs)==1: 
193                        c.pageTabs.append(('Results',session['results']))
194                    elif c.pageTabs[1][0]!='Results':
195                         c.pageTabs.insert(1,('Results',session['results']))
196                    return render_response('results')
197               
198        except ValueError,e:
199            if debug: 
200                raise ValueError,str(e)
201            else:
202                c.xml='<p> Error retrieving documents for %s hits is [%s]</p>'%(hits,e)
203                return render_response('content')
204                               
205        return
206    def __advancedPrompt(self,searchConstraints=None):
207        ''' This provides the advanced search input page '''
208        try:
209            discoveryURL=self.cf.get('SEARCH','discoveryURL')
210            advancedURL=self.cf.get('SEARCH','advancedURL')
211        except:
212            return 'Error, invalid configuration for search interface'
213        #defaults
214        c.bbox='90.0','-180.0','180.0','-90.0'
215        c.startDateDay,c.startDateMon,c.startDateYear='','',''
216        c.endDateDay,c.endDateMon,c.endDateYear='','',''
217        c.textTarget='All'
218        c.searchString=''
219        c.source=['All']
220        #constraints
221
222        if searchConstraints is not None:
223            if searchConstraints['dateRange'] is not None:
224                c.startDateDay,c.startDateMon,c.startDateYear=searchConstraints['dateRange'][0]
225                c.endDateDay,c.endDateMon,c.endDateYear=searchConstraints['dateRange'][1]
226            if searchConstraints['bbox'] is not None:
227                c.bbox=searchConstraints['bbox']
228            if searchConstraints['textTarget'] is not None:
229                c.textTarget=searchConstraints['textTarget']
230            if searchConstraints['searchString'] is not None:
231                c.searchString=searchConstraints['searchString']
232            if searchConstraints['scope'] is not None:
233                c.source=searchConstraintss['scope']
234               
235        return render_response('advanced')
236       
237    def __checkbox(self,bbox):
238        m='Invalid bounding box dimensions entered - limits are '
239        if float(bbox[0])>90.0 or float(bbox[3])<-90.:
240            self.message=m+'+90 (N), -90 (S)!'
241        if float(bbox[1])<-180. or float(bbox[2])>180.:
242            if self.message=='':self.message=m
243            self.message=self.message[:-1]+' -180 (W), 180 (E)!'
244           
245    def __checkform(self,expected):
246        ''' Simply checks the inputs to make sure the elements in expected are present '''
247        message="An incomplete NDG search form was received: "
248        for i in expected:
249            if i not in self.inputs: 
250                self.message=message+i
251        if self.message!='':self.message+='[%s]'%self.inputs
252               
253    def __checkdates(self,dateRange):
254        ''' Check input dates for sanity '''
255       
256        if not ValidDate(dateRange[0])*ValidDate(dateRange[1]):
257            self.message='Input dates are not valid [%s]'%dateRange
258        elif JulDay(dateRange[0])>=JulDay(dateRange[1]):
259            self.message='Second date must be after first date'
260       
261    def __buildconstraints(self,dateRange,bbox,scope,searchString):
262        ''' Just build a constraint string '''
263        return constraints(dateRange=dateRange,bbox=bbox,scope=scope,searchString=searchString)
264       
265    #def oneLineSearch(self):
266    #    try:
267    #        discoveryURL=self.cf.get('SEARCH','discoveryURL')
268    #        oneLiner=DiscoveryTemplate.oneLiner
269    #    except:
270    #        return 'Error, invalid configuration for search interface'
271    #    return DiscoveryTemplate.searchTextOneLine%locals() 
272   
273    def semantic(self):
274        c.constraints=request.environ['QUERY_STRING']
275        return render_response('semantic',fragment=True)
Note: See TracBrowser for help on using the repository browser.