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

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

Fix (I hope) for ticket:818 (in reopened form)

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