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

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

Improvements associated with ticket:733

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?
35        if self.inputs.keys()==[]:
36            self.html+='<div id="superPad">'
37            self.standardInterface()
38            self.html+='</div>'
39            return
40        elif self.inputs.keys()==['advanced']:
41            self.advancedInterface()
42            return
43        elif self.inputs.keys()==['help']:
44            self.helpInterface(0)
45            return
46        elif self.inputs.keys()==['help','advanced']:
47            self.helpInterface(1)
48            return
49       
50        #check simplest text issues common to both simple and advanced search
51        expected=['advanced','textTarget','searchString']
52        self.__checkform(expected)
53        if self.message!='': return
54       
55        #the following may also be present
56        continuations={'start':1,'howmany':10}
57        for i in continuations:
58            if i not in self.inputs: self.inputs[i]=continuations[i]
59           
60        advanced=int(self.inputs['advanced'])
61        self.advanced=advanced
62       
63        self.html=''
64        if not advanced:
65            self.doText(self.inputs['searchString'],self.inputs['textTarget'],
66                        self.inputs['start'],self.inputs['howmany'])
67        else:
68            #check content
69            expected=['timeLimit','startDateDay','startDateMon','startDateYear',
70                        'endDateDay','endDateMon','endDateYear','spaceLimit',
71                        'bboxN','bboxE','bboxS','bboxW',
72                        'sourceLimit']
73            self.__checkform(expected)
74            if self.message!='': return self.error()
75             
76            if int(self.inputs['sourceLimit']):
77                scope=[]
78                if 'sourceMDIP' in self.inputs:
79                    if self.inputs['sourceMDIP']: scope.append('MDIP')
80                if 'sourceNERC' in self.inputs:
81                    if self.inputs['sourceNERC']: scope.append('NERC_DDC')
82            else:
83                scope=None
84               
85            if int(self.inputs['spaceLimit']):
86                bbox=[self.inputs['bboxN'],self.inputs['bboxS'],self.inputs['bboxW'],self.inputs['bboxE']]
87                self.__checkbox(bbox)
88                if self.message!='': return self.error()
89            else:
90                bbox=None
91               
92            if int(self.inputs['timeLimit']):
93                dateRange=[(self.inputs['startDateDay'],self.inputs['startDateMon'],self.inputs['startDateYear']),
94                           (self.inputs['endDateDay'],self.inputs['endDateMon'],self.inputs['endDateYear'])]
95                self.__checkdates(dateRange)                 
96                if self.message!='': return self.error()
97                       
98            else:
99                dateRange=None
100 
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):
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,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        if self.advanced:
137            self.advancedInterface()
138        else:
139            self.standardInterface()
140           
141    def message(self,message):
142        ''' Layout a message to the user '''
143        self.html='<div class="message"><p>%s</p></div>'%message
144       
145   
146    def doText(self,searchString,textTarget,start,howmany,scope=None,dateRange=None,bbox=None):
147        ''' Carry out a text search for <searchString>
148        in the <textTarget> where the accepted text target values are controlled
149        by the DiscoveryTemplate GUI, and are: All, Authors, Parameters '''
150       
151        self.oneLineSearch()
152        start,howmany=int(start),int(howmany)  # url arguments need conversion ...
153       
154        ws=NS.ndgSearch(logger=self.logger)
155        documents=ws.search(searchString,start=start,howmany=howmany,target=textTarget,
156                            scope=scope,dateRange=dateRange,bbox=bbox)
157        if ws.error !=None:
158            for i in ws.error:
159                self.html+='<p>%s</p>'%i
160            return
161       
162        hits=ws.hits
163        id=ws.serverSessionID
164        state=self.__setState(id,searchString,hits,start,howmany)
165        if hits==0: 
166            self.html+=self.message('No records found')
167        else:
168            try:
169                results=ws.getLabelledDocs(format='DIF')
170                difs=[]
171                errors=[]
172                for result in results: 
173                    obj=ndgObject(result[0])
174                    obj.setConfig(self.config)
175                    try:
176                        difs.append(DIF(result[1],ndgObj=obj))
177                    except ValueError,e:
178                        errors.append((result[0],str(e)))
179                if results==[]:
180                    self.html+=self.message('No results for "%s"!</p>'%searchString)
181                elif difs==[]:
182                    self.html+=self.message('No usable results for "%s"!'%searchString) 
183                else:
184                    if errors<>[]:
185                        self.html+='<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                        self.html+=' (unfortunately %s hits matched unformattable documents from %s, an internal error has been logged):</p>'%(len(errors),dp)
195                        mailError('b.n.lawrence@rl.ac.uk','DIF errors',str(errors),server=self.mailServer)
196                    self.html+=renderDiscoverySet(difs,state,self.config)
197            except ValueError,e:
198                if debug: 
199                    raise ValueError,str(e)
200                else:
201                    self.html='<p> Error retrieving documents for %s hits is [%s]</p>'%(hits,e)
202                               
203        #self.standardInterface()
204        return
205               
206
207    def standardInterface(self):
208       
209        try:
210            helpAddress=self.config.get('SEARCH','helpURL')
211            discoveryURL=self.config.get('SEARCH','discoveryURL')
212            advancedURL=self.config.get('SEARCH','advancedURL')
213        except:
214            self.message='Error, invalid configuration for search interface'
215            self.html+=''
216            return
217       
218        self.html+=DiscoveryTemplate.main%locals()
219        return
220   
221    def advancedInterface(self):
222       
223        try:
224            helpAddress=self.config.get('SEARCH','helpURL')
225            discoveryURL=self.config.get('SEARCH','discoveryURL')
226            advancedURL=self.config.get('SEARCH','advancedURL')
227        except:
228            self.message='Error, invalid configuration for search interface'
229            self.html=''
230            return
231        advancedSubmit=DiscoveryTemplate.advancedSubmit%locals()
232        searchText=DiscoveryTemplate.searchText
233        searchTime=DiscoveryTemplate.searchTime
234        searchArea=DiscoveryTemplate.searchArea
235        searchSource=DiscoveryTemplate.searchSource
236        self.html+=DiscoveryTemplate.advanced%locals()
237        return
238   
239    def helpInterface(self,advanced):
240        if advanced:
241            self.advancedInterface()
242        else:
243            self.standardInterface()
244        helpFile=self.config.get('HELP','helpFile')
245        f=file(helpFile,'r')
246        self.html+=f.read()
247        return
248       
249    def oneLineSearch(self):
250        try:
251            discoveryURL=self.config.get('SEARCH','discoveryURL')
252        except:
253            self.message='Error, invalid configuration for search interface'
254            self.html=''
255            return
256        self.html+=DiscoveryTemplate.searchTextOneLine%locals()
257       
258       
Note: See TracBrowser for help on using the repository browser.