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

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

Look and feel of result set is now close to Kay's concepts.

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