source: MILK/trunk/milk_server/milk_server/controllers/browse/retrieve.py @ 4959

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/MILK/trunk/milk_server/milk_server/controllers/browse/retrieve.py@4959
Revision 4959, 11.8 KB checked in by cbyrom, 12 years ago (diff)

Update MILK stack to use the new ndgCommon clients suite + improve
tests by adding scaffold to do proper tidyups after tests run.

Line 
1
2import logging
3from paste.request import parse_querystring
4from xml.parsers.expat import ExpatError
5from milk_server.lib.base import *
6from milk_server.lib import Utilities
7from milk_server.lib import mailer
8from milk_server.lib.ndgInterface import ndgInterface
9from ndg.common.src.lib.ETxmlView import et2text, et2html
10from ndg.common.src.models import stubB, DIF, ndgObject
11from ndg.common.src.models.ndgObject import ndgObject
12from ndg.common.src.models.Atom import Atom
13from ndg.common.src.models.vocabtermdata import VocabTermData as VTD
14from ndg.common.src.clients.xmldb.eXist.searchclient import SearchClient
15
16class RetrieveController(BaseController):
17    ''' Provides the pylons controller for retrieving NDG documents. The simple model
18    is now that an attempt to retrieve/uri will parse the uri, read the config file,
19    and if the local server name is not the same as the uri server name. '''
20   
21    def __setup(self,uri):
22        ''' Common setup stuff for all the actions on this controller '''
23        logging.info("Setting up RetrieveController")
24        self.cf=request.environ['ndgConfig']
25        try:
26            self.uri=ndgObject(uri, config=self.cf)
27        except ValueError,e:
28            return e
29
30        self.inputs=dict(parse_querystring(request.environ))
31
32        # NB: we could have two types of query string argument:
33        #   format= (raw,html) and
34        #   outputSchema=(original, someSchema)
35        self.format=''
36        if 'format' in self.inputs: 
37            self.format=self.inputs['format']
38        self.outputSchema=''
39        if 'outputSchema' in self.inputs: 
40            self.outputSchema=self.inputs['outputSchema']
41
42        # Add selected granules to context
43        #c.selectedGranules = [g_uri for g_uri, g_name in session.get('selection', [])]
44                             
45        logging.info("RetrieveController set up")
46        return 0
47       
48    def index(self,uri):
49        ''' Returns the document unadorned in anyway, i.e. the raw xml'''
50        status=self.__setup(uri)
51        if status:
52            c.xml='<p>%s</p>'%status
53            response.status_code = 400
54            return render('error')
55       
56        interface = ndgInterface()
57        status,x=interface.GetXML(uri,outputSchema=self.outputSchema)
58        if status:
59            #(the return object x is an ET object)
60            c.xml = et2text(x)
61            response.headers['Content-Type'] = 'application/xml'
62            response.write(c.xml)
63        else:
64            e=404
65            if x.startswith('<p> Access'): e=401
66            response.status_code = e
67            return render('error')
68
69    def viewAssociatedData(self, type, uri):
70        '''
71        Get the specified data associated with the uri
72        @param type: type of associated data to lookup - currently VTD.DEPLOYMENT_TERM
73        or VTD.DE_TERM
74        @param uri: valid ndg uri
75        @return rendered genshi deployments template
76        '''
77        logging.info("Getting %s data for '%s'" %(type, uri))
78        status=self.__setup(uri)
79        if status:
80            c.xml='<p>%s</p>'%status
81            response.status_code = 400
82            return render('error')
83
84        try:
85            # NB, we should have stored the current atom data - so look this up now
86            atom = session.get('currentAtom')
87            if atom:
88                c.atom = atom
89            else:
90                interface = ndgInterface()
91                status,x=interface.GetXML(uri,outputSchema=self.outputSchema, useCache=False)
92                c.xmlh=x
93                c.atom = Atom(xmlString=str(x), ndgObject = self.uri)
94           
95            # NB, there are two routes through here - if we're viewing a data entity,
96            # the deployment links are available directly from the atom; if not we
97            # need to look them up
98            lookupIndirectReferences = True
99            if c.atom.isDE():
100                lookupIndirectReferences = False
101           
102            searchClient = SearchClient(dbHostName = self.cf.get('NDG_EXIST','local'),
103                                        configFileName = self.cf.get('NDG_EXIST','passwordFile'))
104           
105            c.atom.lookupAssociatedData(type, searchClient, 
106                                        lookupIndirectReferences = lookupIndirectReferences)
107
108            template = 'atom_editor/deployments_data'
109            if type == VTD.DE_TERM:
110                template = 'atom_editor/data_entities_data'
111
112            # store the atom to retain the looked up info
113            session['currentAtom'] = c.atom
114            session.save()
115               
116            logging.info("- %s data retrieved - now rendering" %type)
117            return render('genshi', template)
118       
119        except ExpatError, e:
120            c.xml='XML content is not well formed'
121            c.doc=str(x)
122            response.status_code = 400
123            logging.error("Error retrieving [%s] - XML content: %s" % (uri, e))
124            return render('error')
125
126        except Exception, e:
127            #we may be showing an xml document ... but it could go wrong if
128            #we have crap content ...
129            c.xml='Unexpected error [%s] viewing [%s]'%(str(e), uri)
130            c.doc=''
131            response.status_code = 400
132            logging.error(c.xml)
133            return render('error')
134
135       
136       
137    def view(self,uri):
138        ''' Returns either an html marked up version of the xml, or a properly laid
139        out version of the document '''
140        c.doc=None
141        # NB, this sets up self.uri as an ndgObject
142        status=self.__setup(uri)
143        if status:
144            c.xml='<p>%s</p>'%status
145            response.status_code = 400
146            return render('error')
147
148        logging.info("Retrieving document to view")
149        useCache = True
150        viewFormat=self.uri.schema
151        # NB, don't use cache if we're looking up atoms as these can change quickly
152        # when using the atom editor
153        if viewFormat == ndgObject.ATOM_DOC_TYPE or \
154            viewFormat ==  ndgObject.ATOM_BACKUP_DOC_TYPE:
155            useCache = False
156           
157        interface = ndgInterface()
158        #(the return object x is an ET object)
159        status,x=interface.GetXML(uri,outputSchema=self.outputSchema, useCache=useCache)
160        c.title='Viewing [%s]'%self.uri
161       
162        # NB, legacy code uses kid templates - newer stuff should use genshi
163        templateType = "kid"
164        if status:
165            logging.debug("Document retrieved ok - now processing results")
166
167            if self.outputSchema!='': 
168                viewFormat=self.outputSchema
169
170            logging.debug("Doc format: %s, View format: %s" \
171                           %(self.format, viewFormat))
172
173            name=str(self.uri)
174            if self.format=='xml':
175                c.xml = et2html(x)
176                renderTemplate = 'content'
177                c.tab='Details'
178
179            elif self.format=='raw':
180                c.xml = et2text(x)
181                response.headers['Content-Type'] = 'application/xml'
182                return response.write(c.xml)
183               
184            elif viewFormat == ndgObject.ATOM_DOC_TYPE or \
185                viewFormat ==  ndgObject.ATOM_BACKUP_DOC_TYPE:
186                renderTemplate = 'atom_editor/atom_editor'
187                c.xmlh = x
188                c.atom = Atom(xmlString=x, ndgObject = self.uri)
189               
190                # get the current publication state
191                edc = Utilities.getExistClient(c.atom.ME.providerID)
192                c.atom.state = edc.getAtomPublicationState(c.atom.datasetID, 
193                                                           c.atom.ME.providerID)
194               
195                c.title = 'Viewing [%s]'%self.uri
196                c.deploymentsURL = h.url_for(controller='browse/retrieve', \
197                                             action='viewAssociatedData', \
198                                             type = VTD.DEPLOYMENT_TERM, \
199                                             uri = self.uri)
200                c.dataEntitiesURL = h.url_for(controller='browse/retrieve', \
201                                             action='viewAssociatedData', \
202                                             type = VTD.DE_TERM, \
203                                             uri = self.uri)
204                templateType = "genshi"
205                # store the atom for easy re-use by asynch calls
206                # - primarily for the viewAssociatedData() method here
207                session['currentAtom'] = c.atom
208                session.save()
209
210            elif viewFormat == ndgObject.MOLES_DOC_TYPE:
211                renderTemplate = 'browse/stubB'
212                c.doc=stubB.stubB(x, self.cf)
213                name=c.doc.abbreviation
214               
215            elif viewFormat == ndgObject.NDGA0_DOC_TYPE:
216                renderTemplate = 'content'
217                name=self.uri.localID
218                #for now we'll handle as pretty print xml
219                c.xml = et2html(x)
220                c.tab='Details'
221               
222            elif viewFormat == ndgObject.DIF_DOC_TYPE or viewFormat == ndgObject.BROWSE_DIF_DOC_TYPE:
223                renderTemplate = 'browse/dif'
224                c.doc=DIF.DIF(x, et=1, ndgObj=self.uri)
225                name=c.doc.name
226               
227            elif viewFormat == ndgObject.NUMSIM_DOC_TYPE:
228                renderTemplate = 'browse/numsim'
229                c.xmlh=x
230                name=x.findtext('NS_Name')
231                c.name=name
232               
233            else:
234                c.xml = et2html(x)
235                renderTemplate = 'content'
236           
237            needed=0
238            if 'lastViewed' not in session: 
239                needed=1
240               
241            session['lastViewed']=h.current_url()
242            if needed: 
243                c.pageTabs.append(('Details',session['lastViewed']))
244           
245            session.save()
246            code=200
247        else:
248            renderTemplate = 'error'
249            if x.startswith('<p> Access Denied'):
250                code=401
251            else: code=400
252            c.xml='%s'%x
253            logging.error(x)
254           
255        response.status_code = code
256        try:
257            return render(templateType, renderTemplate)
258       
259        except ExpatError, e:
260            c.xml='XML content is not well formed'
261            c.doc=str(x)
262            response.status_code = 400
263            logging.error("Error retrieving [%s] - XML content: %s" % (uri, e))
264            return render('error')
265
266        except Exception, e:
267            #we may be showing an xml document ... but it could go wrong if
268            #we have crap content ...
269            c.xml='Unexpected error [%s] viewing [%s]'%(str(e), uri)
270            c.doc=''
271            response.status_code = 400
272            logging.error(c.xml)
273            return render('error')
274   
275    def askCorrect(self,uri):
276        ''' Provide a form (ajaxaciously) so that a user can correct a metadata record'''
277        status=self.__setup(uri)
278        c.uri=self.uri
279        if status: return response.write(status)
280        return render('correct',fragment=True)
281
282   
283    def correct(self,uri):
284        ''' Receive a correction form to update a record and post it to the holder '''
285        status=self.__setup(uri)
286        if 'ndgSec' not in session:
287            return response.write('Not Logged In')
288        body='Metadata Change Request for %s'%uri
289        payload='<Change><uri>%s</uri><from>%s</from><Contents>%s</Contents></Change>'%(
290            self.inputs['Identifier'],self.inputs['Submitter'],self.inputs['Comment'])
291        name='ChangeRequestFor_%s.xml'%uri
292        status,message=mailer.mailHandler([self.cf.get('DEFAULT','metadataMaintainer'),],
293                       body,body,xmlAttachments=[(payload,name),],
294                       server=self.cf.get('DEFAULT','mailserver'))
295        if status:
296            c.xml='<p>Success: Mail sent to metadata maintainer</p>'
297        else:
298            c.xml=message
299        return render('content')
Note: See TracBrowser for help on using the repository browser.