source: TI07-MOLES/trunk/StubB/XSLT/browse/portal/cgi/browse/browseCGI.py @ 1182

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI07-MOLES/trunk/StubB/XSLT/browse/portal/cgi/browse/browseCGI.py@1182
Revision 1182, 11.7 KB checked in by lawrence, 14 years ago (diff)

A large number of small modifications to browse
dealing with a range of bugs ...

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2# CGI Script to support prototype NDG MOLES_Portal (Browse) functionality
3# Bryan Lawrence, April, 2006
4
5import cgi
6#import cgitb;ctitb.enable()
7
8import os
9import ElementTree as ET
10
11from insecure import *
12from secure import *
13from stubB import *
14
15from renderEntity import renderEntity
16from renderPage import renderPage
17from renderDiscoverySet import renderDiscoverySet
18from htmlUtilities import selector,hyperlink
19from Utilities import *
20from ETxmlView import *
21from DiscoveryWS import *
22from DIF import DIF
23import base64
24
25import Cookie
26
27class BrowseSession:
28       
29        ''' Holds the browse and select history '''
30       
31        def __init__(self,cookie,config):
32               
33                '''Instantiate with an unsecured browse session (security only
34                required if a secure resource is the target) '''
35                self.config=config
36                self.rawCookie=cookie
37                self.cookie=Cookie.SimpleCookie(cookie)
38                self.history=RingBuffer(10)
39                self.selected=RingBuffer(5)
40             
41                self.__load()
42                       
43        def __toXML(self):
44                ''' Used to serialise the session into a cookie string '''
45                xml='<ndgCookie><bh>'
46                for uri,name in self.getHistory():
47                        xml+='<i><u>%s</u><n>%s</n></i>'%(base64.urlsafe_b64encode(uri),name)
48                xml+='</bh><sh>'
49                for uri,name in self.getSelected():
50                    xml+='<i><u>%s</u><n>%s</n></i>'%(base64.urlsafe_b64encode(uri),name)
51                xml+='</sh></ndgCookie>'
52                return xml
53               
54        def __load(self):
55            ''' get lists of URI values out of a cookie '''
56            try:
57                e=ET.fromstring(self.cookie['history'].value)
58                for se in e:
59                    for item in se:
60                        uri,name=item.find('u'),item.find('n')
61                        self.__addTo(base64.urlsafe_b64decode(uri.text),name.text,se.tag)
62            except KeyError:
63                pass
64                       
65        def __addTo(self,uri,name,tag,ignore=False):
66            d={'bh':self.history,'sh':self.selected}
67            current=d[tag].tolist()
68            if (uri,name) not in current or ignore:
69                d[tag].append((uri,name))
70                       
71        def addToHistory(self,uri,name,ignore=False):
72           ''' Add a URI to the session history'''
73           self.__addTo(uri,name,'bh',ignore)
74                       
75        def getHistory(self):
76           ''' Return a list of the items in the history '''
77           return self.history.tolist()
78       
79        def addToSelected(self,uri,name,ignore=False):
80            ''' Add a URI to the selected items '''
81            self.__addTo(uri,name,'sh',ignore)
82            self.__addTo(uri,name,'bh',ignore)
83                   
84        def getSelected(self):
85            ''' Return a list of selected items '''     
86            return self.selected.tolist()       
87       
88        def makeCookie(self,ndgSec=None):
89                ''' Create a local cookie '''
90                import md5,time,base64
91                # start by creating a unique session id
92                m=md5.new()
93                m.update('this is a seed string')
94                m.update(str(time.time()))
95                cookie=Cookie.SimpleCookie()
96                cookie['session']=base64.encodestring(m.digest())[:-3].replace("/", "$")
97                cookie['history']=self.__toXML()
98                if ndgSec is not None:
99                    cookie['NDG-ID1']=ndgSec[0]
100                    cookie['NDG-ID2']=ndgSec[1]
101                return cookie
102       
103class Request:
104    ''' Holds the request URL etc '''
105    def __init__(self,env):
106        self.env=env
107        self.URL='http://%s:%s%s'%(env.get('SERVER_NAME'),env.get('SERVER_PORT'),
108        env.get('SCRIPT_NAME'))
109        qs=env.get('QUERY_STRING')
110        if qs!='': self.URL+='?'+qs
111
112class CGIcontroller:
113        ''' Currently holds the cgi environment and controls '''
114       
115        def __init__(self,config):
116                ''' Instantiate the CGI environment'''
117                #
118                # Need to refactor all of this to use the request class and then move
119                # the request class out into the utilities ...
120                #
121                self.env=os.environ
122                self.path=self.env.get('PATH_INFO','/')
123                self.FieldStorage=getURLdict(cgi.FieldStorage())
124                self.config=config
125                self.response=Response()
126                self.request=Request(self.env)
127                self.requestURL=self.request.URL
128                self.selector=selector(self.requestURL,'select',config.get('layout','selectI'))
129                self.serviceFile=self.config.get('services','serviceFile')
130               
131
132        def makeGateway(self,cookie=None):
133                ''' Make connection to NDG security and load what is necessary for
134                an NDG cookie to be written '''
135                aa=self.config.get('security','localAA',None)
136                if 'NDG-ID1' in self.FieldStorage and 'NDG-ID2' in self.FieldStorage:
137                    #this is a redirect following login ...
138                    cmdLine=(self.FieldStorage['NDG-ID1'],self.FieldStorage['NDG-ID2'])
139                else: cmdLine=None
140                self.ndgGate=gateway2NDGsession(self.requestURL,self.config,aa,cookie=self.cookie,cmdLine=cmdLine)
141                self.ndgSec=cmdLine
142
143        def goforit(self):
144                ''' This method actually responds to the user'''
145               
146                self.ViewTextOnly,self.ViewXML=0,0
147               
148                #Instantiate the Session Environment
149                cookie=self.env.get('HTTP_COOKIE',None)
150                self.session=BrowseSession(cookie,self.config)
151                self.cookie=self.session.cookie # now a cookie class object ...
152                if self.config.logfile is not None: self.config.log(self.cookie)
153               
154                #this is where we invoke NDG security setup, even if we don't
155                #need it ...
156                self.makeGateway()
157               
158                #this will do for the moment, although I'd rather the whole
159                #URI was self consistent using the request object.
160               
161                if 'select' in self.FieldStorage:
162                    n=self.FieldStorage['name']
163                    s=ServiceBinding(n=n,
164                                     entryID=self.FieldStorage['select'],
165                                     serviceFile=self.serviceFile)
166                    self.session.addToSelected(s.url,n)
167
168                    #we also need to trim the selector off the current requestURL
169                    self.requestURL=self.requestURL[0:self.requestURL.find('&select')]
170                    self.selector.baseURL=self.requestURL
171               
172                #use name as an error return as well in the following calls ...
173                if 'uri' in self.FieldStorage:
174                    self.uri=self.FieldStorage['uri']
175                    content,name=self.__browse()
176                elif 'search' in self.FieldStorage:
177                    self.searchType=self.FieldStorage['search']
178                    content,name=self.__search()
179                else: 
180                    content,name=self.error('No URI or search string. Begin browsing via search box or pass a specific URI argument.'),'No URI'
181
182                if not self.ViewTextOnly:
183                    historyHTML='<p>'
184                    for item in self.session.getHistory():
185                        historyHTML+=hyperlink(item[1],item[0])+'<br/>'
186                    historyHTML+='</p>'
187                    selectHTML='<p>'
188                    for item in self.session.getSelected():
189                        selectHTML+=hyperlink(item[1],item[0])+'<br/>'
190                    selectHTML+='</p>'
191                    self.response.content=renderPage(
192                        content,historyHTML,selectHTML,name,self.config)
193                else:
194                    self.response.content=content
195                self.response.cookie=self.session.makeCookie(ndgSec=self.ndgSec)
196                return self.response
197               
198        def __browse(self):
199                ''' Handle orthodox browsing '''
200               
201                if self.FieldStorage.has_key('text'):
202                    self.ViewTextOnly=1
203                elif self.FieldStorage.has_key('xml'):
204                    self.ViewXML=1
205               
206                format='NDG-B0'
207                if self.FieldStorage.has_key('D'):format='DIF'
208               
209                #get the xml document
210                db=self.config.get('db','exist',None)
211                jar=self.config.get('services','jarLoc')
212                javabin=self.config.get('services','javaBinary')
213                xml=insecureGetDoc(self.uri,db=db,format=format,jar=jar,javaBin=javabin)
214               
215                #create document instance
216                if format=='NDG-B0':
217                    self.b=stubB(xml,serviceFile=self.serviceFile)
218                elif format=='DIF':
219                    self.b=DIF(xml,serviceFile=self.serviceFile)
220               
221                if self.b.xml is None:
222                    content=self.error('Unable to obtain record [%s] from database'%self.uri)
223                    return content,0
224                else:
225                    self.session.addToHistory(self.b.binding.url,self.b.abbreviation)
226                    if  self.b.constraints.exist:
227                        # we need to evaluate them
228                        #result=self.ndgGate.check(self.b.constraints.SimpleCondition)
229                        try:
230                             result=self.ndgGate.check(self.b.constraints.SimpleCondition)
231                             if result=='AccessGranted': 
232                                access=1
233                             else:
234                                access=0
235                        except Exception,e:
236                             #unable to make ndggate check ... deny
237                             access=0
238                             result=self.error('Unable to connect to security gateway, access to secure resource denied')
239                             result+='<p>%s</p>'%str(self.b.constraints.SimpleCondition)
240                             result+='<p>%s</p>'%str(e)
241                    else:
242                        access=1
243                    if access:
244                        name=self.b.name
245                        if self.ViewTextOnly:
246                            self.response.contentType='text/plain'
247                            content=et2text(self.b.tree)
248                        elif self.ViewXML==1:
249                            content=et2html(self.b.tree)
250                        else:
251                            content=self.b.toHTML(self.config)
252                    else:
253                        name='NDG Browse'
254                        content=result
255
256                    return content,name
257               
258        def __search(self):
259            ''' Handle simple searching within the context of the browse '''
260            if 'SEARCHSTRING' in self.FieldStorage:
261                searchString=self.FieldStorage['SEARCHSTRING']
262                title='Search for '+searchString
263                try:
264                    ws=DiscoveryWS(wsdl=self.config.get('services','searchWSDL'))
265                except Exception, e:
266                    return self.error('<p>%s<br/>%s'%(e,'Unable to connect to Search BackEnd')),'Error'
267                try:
268                    hits=ws.SearchFullText(searchString)
269                    state=DiscoveryState(ws.sessID,self.requestURL,hits,stride=10)
270                    results=ws.GetResults(offset=state.offset,number=state.stride)
271                except TypeError:
272                    # this is not what these web services should do, they should
273                    # return an empty set or something which matches the argument
274                    # list, but at least I think this traps the empty set.
275                    return self.error('No records found'),title
276                difs=[]
277               
278                for result in results: difs.append(DIF(result,serviceFile=self.serviceFile))
279                html=renderDiscoverySet(difs,state,selector=self.selector,
280                               summary=1,spatial=1,temporal=1,services=1)
281               
282                return html,title
283            else:
284                return self.error('No valid search option'),'Error'
285             
286        def error(self,message):
287                ''' Construct a nice formal response, but don't throw a 404 ... '''
288                return '<p>Error: %s</p>'%message
289               
Note: See TracBrowser for help on using the repository browser.