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

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

Sundry errors fixed to support browse under apache ...

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