source: TI07-MOLES/trunk/PythonCode/wsgi/DiscoveryGUI.py @ 2545

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI07-MOLES/trunk/PythonCode/wsgi/DiscoveryGUI.py@2545
Revision 2545, 12.2 KB checked in by lawrence, 12 years ago (diff)

Woops, forgot to commit these last night.
This is the date ordering change for discovery

Line 
1import DiscoveryTemplate
2from paste.request import parse_querystring
3import ndgSearch as NS
4from DIF import DIF
5from renderDiscoverySet import renderDiscoverySet
6from DiscoveryState import DiscoveryState
7from Utilities import myConfig,mailError
8from ndgObject import ndgObject
9from Date import *
10debug=0
11class DiscoveryGUI:
12    ''' This class handles the NDG gui search interface, and is intimately related to the
13    template.py code which provides the gui interface and the variables which need to be populated '''
14   
15    #The key options are either there is content in the inputdictionary, in which case we have a
16    #search to do, and then some results to present, or there is none, in which case we present
17    #an appropriate interface back to the user (remembering that we only produce part of a page,
18    #this can all be embedded in anything else.
19   
20    def __init__(self,environ,config,logger):
21        ''' Takes a dictionary of variables which have been populated by the cgi (or whatever)
22        handler, and tests them for sanity before handing queries off to the NDG backend xqquery
23        web service '''
24       
25        inputs=dict(parse_querystring(environ))
26        self.inputs=inputs
27        self.environ=environ
28        self.config=config
29        self.logger=environ['wsgilog.logger']
30        self.mailServer=self.config.get('DEFAULT','mailServer','outbox.rl.ac.uk')
31        self.message=''
32        self.html=''
33       
34        #is this simply a blank request for an interface? In this version,
35        if self.inputs.keys()==[]:
36            self.advancedInterface2()
37            return
38        elif self.inputs.keys()==['advanced']:
39            self.advancedInterface2()
40            return
41        elif self.inputs.keys()==['help']:
42            self.helpInterface(0)
43            return
44        elif self.inputs.keys()==['help','advanced']:
45            self.helpInterface(1)
46            return
47       
48        #check simplest text issues common to both simple and advanced search
49        expected=['advanced','textTarget','searchString']
50        self.__checkform(expected)
51        if self.message!='': return
52       
53        #the following may also be present
54        continuations={'start':1,'howmany':10}
55        for i in continuations:
56            if i not in self.inputs: self.inputs[i]=continuations[i]
57           
58        advanced=int(self.inputs['advanced'])
59        self.advanced=advanced
60       
61        self.html=''
62       
63        if not advanced:
64            self.doText(self.inputs['searchString'],self.inputs['textTarget'],
65                        self.inputs['start'],self.inputs['howmany'])
66        else:
67            #check content
68            expected=['startDateDay','startDateMon','startDateYear',
69                        'endDateDay','endDateMon','endDateYear',
70                        'bboxN','bboxE','bboxS','bboxW']
71            self.__checkform(expected)
72            if self.message!='': return self.error()
73           
74            # ------------- Handle scope from radio button on form -------
75            if 'source' in self.inputs:
76                # the WSDL expects a list, we're just providing one ... via a radio ...
77                scope=[self.inputs['source']]
78                if scope==['All']: scope=None
79            else:
80                scope=None
81           
82            # ------------- Handle Location Bounding --------
83            # default form has a global bounding box
84            bbox=[self.inputs['bboxN'],self.inputs['bboxS'],self.inputs['bboxW'],self.inputs['bboxE']]
85            self.__checkbox(bbox)
86            if self.message!='': return self.error()
87               
88            # ------------- Handle Date Ranges ---------------
89            try:
90                dateRange=[(self.inputs['startDateDay'],iMonth(self.inputs['startDateMon']),self.inputs['startDateYear']),
91                           (self.inputs['endDateDay'],iMonth(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!='': return self.error()
99                       
100            # ------------- ok, now go do the search -----------
101            self.doText(self.inputs['searchString'],self.inputs['textTarget'],
102                 self.inputs['start'],self.inputs['howmany'],scope=scope,dateRange=dateRange,bbox=bbox)
103           
104        return
105           
106           
107    def __checkbox(self,bbox):
108        if float(bbox[0])>90.0 or float(bbox[1])<-90. or float(bbox[2])<-180. or float(bbox[3])>180.:
109            self.message='Invalid bounding box dimensions entered (limits 90,-90,-180,180)'
110           
111    def __checkform(self,expected):
112        ''' Simply checks the inputs to make sure the elements in expected are present '''
113        message="An incomplete NDG search form was received: "
114        for i in expected:
115            if i not in self.inputs: 
116                self.message=message+i
117                self.html='<p>%s</p>'%self.message
118               
119    def __checkdates(self,dateRange):
120        ''' Check input dates for sanity '''
121        print dateRange,ValidDate(dateRange[0]),ValidDate(dateRange[1])
122        if not ValidDate(dateRange[0])*ValidDate(dateRange[1]):
123            self.message='Input dates are not valid'
124        elif JulDay(dateRange[0])>=JulDay(dateRange[1]):
125            self.message='Second date must be after first date'
126               
127    def __setState(self,id,searchString,hits,offset,stride,constraints):
128        ''' Sets the discovery state to be used by external routines '''
129        if hits<stride:stride=hits
130        return DiscoveryState(id,searchString,self.environ,hits,constraints,offset,stride)
131       
132   
133    def error(self):
134        ''' Return a useful error message '''
135        self.html='<div class="error"><p>%s</p></div>'%self.message
136        self.advancedInterface2()
137
138           
139    def message(self,message):
140        ''' Layout a message to the user '''
141        self.html='<div class="message"><p>%s</p></div>'%message
142       
143       
144    def __buildconstraints(self,dateRange,bbox,scope):
145        ''' Just build a constraint string '''
146        constraints=' ('
147        if dateRange is not None: 
148            constraints+='Including&nbsp;%s&nbsp;to&nbsp;%s; '%('%s,%s,%s'%dateRange[0],'%s,%s,%s'%dateRange[1])
149        if bbox is None or bbox==['+90.0','-90.0','-180.0','+180.0']:
150            constraints+='Global; '
151        else: constraints+='Bounding&nbsp;Box:&nbsp;%s,%s,%s,%s; '%tuple(bbox)
152        if scope is not None:
153            constraints+='Restricted to %s; '%scope[0]
154        constraints=constraints[:-2]+')'
155        self.logger.info(constraints)
156        return constraints
157       
158   
159    def doText(self,searchString,textTarget,start,howmany,scope=None,dateRange=None,bbox=None):
160        ''' Carry out a text search for <searchString>
161        in the <textTarget> where the accepted text target values are controlled
162        by the DiscoveryTemplate GUI, and are: All, Authors, Parameters '''
163       
164        self.oneLineSearch()
165        start,howmany=int(start),int(howmany)  # url arguments need conversion ...
166       
167        ws=NS.ndgSearch(logger=self.logger)
168        documents=ws.search(searchString,start=start,howmany=howmany,target=textTarget,
169                            scope=scope,dateRange=dateRange,bbox=bbox)
170        if ws.error !=None:
171            for i in ws.error:
172                self.html+='<p>%s</p>'%i
173            return
174       
175        #build constraints info for report
176        constraints=self.__buildconstraints(dateRange,bbox,scope)
177       
178        hits=ws.hits
179        id=ws.serverSessionID
180        state=self.__setState(id,searchString,hits,start,howmany,constraints)
181        if hits==0: 
182            self.html+='<div class="message"><table><tbody><tr><td>No records found %s.</td></tr></tbody></table></div>'%state.constraints
183        else:
184            try:
185                results=ws.getLabelledDocs(format='DIF')
186                difs=[]
187                errors=[]
188                for result in results: 
189                    obj=ndgObject(result[0])
190                    obj.setConfig(self.config)
191                    try:
192                        difs.append(DIF(result[1],ndgObj=obj))
193                    except ValueError,e:
194                        errors.append((result[0],str(e)))
195                if results==[]:
196                    self.html+=self.message('No results for "%s"!</p>'%searchString)
197                elif difs==[]:
198                    self.html+=self.message('No usable results for "%s"!'%searchString) 
199                else:
200                    if errors<>[]:
201                        self.html+='<p>Search results for "%s"'%searchString
202                        dp=[]
203                        for e in errors:
204                            n=ndgObject(e[0])
205                            if n.repository not in dp: dp.append(n.repository)
206                        if len(dp)<>1: 
207                            dp='[Various Data Providers]'
208                        else:
209                            dp='[%s]'%dp[0] 
210                        self.html+=' (unfortunately %s hits matched unformattable documents from %s, an internal error has been logged):</p>'%(len(errors),dp)
211                        mailError('b.n.lawrence@rl.ac.uk','DIF errors',str(errors),server=self.mailServer)
212                    self.html+=renderDiscoverySet(difs,state,self.config)
213            except ValueError,e:
214                if debug: 
215                    raise ValueError,str(e)
216                else:
217                    self.html='<p> Error retrieving documents for %s hits is [%s]</p>'%(hits,e)
218                               
219        #self.standardInterface()
220        return
221               
222
223    def standardInterface(self):
224       
225        try:
226            helpAddress=self.config.get('SEARCH','helpURL')
227            discoveryURL=self.config.get('SEARCH','discoveryURL')
228            advancedURL=self.config.get('SEARCH','advancedURL')
229        except:
230            self.message='Error, invalid configuration for search interface'
231            self.html+=''
232            return
233       
234        self.html+=DiscoveryTemplate.main%locals()
235        return
236   
237    def advancedInterface(self):
238       
239        try:
240            helpAddress=self.config.get('SEARCH','helpURL')
241            discoveryURL=self.config.get('SEARCH','discoveryURL')
242            advancedURL=self.config.get('SEARCH','advancedURL')
243        except:
244            self.message='Error, invalid configuration for search interface'
245            self.html=''
246            return
247        advancedSubmit=DiscoveryTemplate.advancedSubmit%locals()
248        searchText=DiscoveryTemplate.searchText
249        searchTime=DiscoveryTemplate.searchTime
250        searchArea=DiscoveryTemplate.searchArea
251        searchSource=DiscoveryTemplate.searchSource
252        self.html+=DiscoveryTemplate.advanced%locals()
253        return
254   
255    def advancedInterface2(self):
256        try:
257            discoveryURL=self.config.get('SEARCH','discoveryURL')
258            advancedURL=self.config.get('SEARCH','advancedURL')
259            oneLiner=DiscoveryTemplate.oneLiner
260        except:
261            self.message='Error, invalid configuration for search interface'
262            self.html=''
263            return
264        bboxN,bboxW,bboxE,bboxS='+90.0','-180.0','+180.0','-90.0'
265        startDateDay,startDateMon,startDateYear='','',''
266        endDateDay,endDateMon,endDateYear='','',''
267        self.html+=DiscoveryTemplate.revisedAdvancedSearch%locals()
268       
269   
270    def helpInterface(self,advanced):
271        if advanced:
272            self.advancedInterface()
273        else:
274            self.standardInterface()
275        helpFile=self.config.get('HELP','helpFile')
276        f=file(helpFile,'r')
277        self.html+=f.read()
278        return
279       
280    def oneLineSearch(self):
281        try:
282            discoveryURL=self.config.get('SEARCH','discoveryURL')
283            oneLiner=DiscoveryTemplate.oneLiner
284        except:
285            self.message='Error, invalid configuration for search interface'
286            self.html=''
287            return
288        self.html+=DiscoveryTemplate.searchTextOneLine%locals()
289       
290       
Note: See TracBrowser for help on using the repository browser.