source: MILK/trunk/milk_server/milk_server/controllers/atom_editor/atomeditorcontroller.py @ 5085

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

Fix typo in error reporting.

Line 
1'''
2 Class representing base pylons controller for the atom editor shared functions
3 
4 @author: C Byrom, Tessella Dec 2008
5'''
6import logging, xmlrpclib, cgi, traceback
7from ndg.common.src.models.ndgObject import ndgObject
8from ndg.common.src.lib.utilities import escapeSpecialCharacters
9from milk_server.lib.base import *
10from milk_server.models.ndgdoc import NDGDoc
11from editorconstants import *
12from formencode import htmlfill
13   
14class AtomEditorController(BaseController):
15    '''
16    Provides the pylons controller for shared functions
17    '''
18    STANDARD_SAVE = 1
19    ADD_ASSOCIATIONS = 3
20    REMOVE_ASSOCIATIONS = 4
21
22    def _setup(self, uri=None, loadAtom=True):
23        '''
24        Common setup stuff for all the actions on this controller
25        @keyword uri: uri of the atom to set up
26        @keyword loadAtom: if True, load the atom into c.atom, otherwise don't.
27        Default is True.
28        '''
29        logging.info("Setting up AtomEditorController")
30        self.cf=request.environ['ndgConfig']
31        self.inputs = self.__getTidyInputs()
32
33        if uri:
34            self.ndgObject = ndgObject(uri, config = self.cf)
35
36            self.ndgDoc = NDGDoc(ndgURI = uri, config = self.cf)
37            if loadAtom:
38                self.__prepareDataModel(uri)
39
40        logging.info("AtomEditorController set up")
41
42
43    def __prepareDataModel(self, uri):
44        '''
45        Set up the underlying atom data model - loading the bulk from eXist
46        then updating any input fields appropriately
47        '''
48        logging.info("Preparing underlying data model")
49        logging.info("Retrieving document to edit")
50
51        # NB, passing in the inputs will overwrite any original values with the
52        # user input ones
53        if not self.inputs:
54            self.inputs = self.__getTidyInputs()
55
56        self.ndgDoc.setupDocumentModel(ndgUri = uri, inputs = self.inputs)
57
58        if not self.ndgDoc.status:
59            c.xml = self.ndgDoc.xmlString
60            response.status_code = self.ndgDoc.htmlCode
61            raise SystemError('Problem experienced retrieving atom doc from eXist [%s]' 
62                              %self.ndgDoc.xmlString)
63
64        c.atom = self.ndgDoc.docModel
65
66        # save the current atom - to avoid this needing be recreated by the
67        # asynch viewAssociatedData call
68        session['currentAtom'] = c.atom
69        session.save()
70        logging.info("Data model set up")
71
72
73    def __getTidyInputs(self):
74        '''
75        The inputs can be used generically to specify atom attributes - however
76        some inputs should not be set against the Atom object since they use slots
77        so cannot be pickled - which means saving the atom in the session with fail.
78        This method clears out any unwanted inputs
79        '''
80        logging.debug("Getting pickleable input data")
81        inputs = request.params
82        tidyInputs = {}
83        for key, val in inputs.items():
84            if not isinstance(val, cgi.FieldStorage):
85                tidyInputs[key] = val
86
87        logging.debug("Pickleable data extracted")
88        return tidyInputs
89
90
91    def _unpackErrors(self, e):
92        '''
93        Add exception errors to the common error structures - for use
94        in templates
95        @param e: Exception to add
96        @return errors: dict of errors
97        '''
98        if not c.errors:
99            c.errors = {}
100
101        errorMessage = e.message
102        if g.debugModeOn == 'True':
103            errorMessage = traceback.format_exc()
104
105        c.xml = escapeSpecialCharacters('Unexpected error loading page [%s]' \
106                                        %str(errorMessage))
107        c.doc = ''
108       
109        # unpack errors, if possible - NB, the c.errors value is used by the template
110        # function, displayErrors, which is used by most of the editor templates
111        if isinstance(e, xmlrpclib.Fault):
112            # strip out the exception type - NB, this is usually native library code
113            # and is of no real interest - and will just confuse viewers
114            c.errors['Unexpected error'] = e.faultString.split(':')[-1] 
115
116        if hasattr(e, 'unpack_errors'):
117            c.errors.update(e.unpack_errors())
118           
119        else:
120            c.errors['Unexpected error'] = [c.xml]
121
122        # tidy up errors - escaping any xml tags, if necessary
123        for key, errors in c.errors.items():
124            newErrors = []
125            for error in errors:
126                for err in error.split('<br/>'):
127                    newErrors.append(escapeSpecialCharacters(err))
128            c.errors[key] = newErrors
129       
130        return c.errors
131
132
133    def _handleError(self, e, template='atom_editor/error'):
134        '''
135        Handle exceptions thrown; if debug mode on, display full stack trace
136        in output, otherwise just show basic error message in error template
137        @param e: Exception to process
138        @keyword template: template to render - 'error' is the default - NB, if
139        an alternative is specified it should have a div with class set to 'error'
140        containing the variable, c.xml to display properly
141        '''
142        self._unpackErrors(e)
143        logging.error(c.xml)
144        response.status_code = 400
145        return render("genshi", template)
146
147
148    def savePageAndRender(self, template, **inputs):
149        '''
150        Save the current path info - to provide a memory function when changing
151        tabs + render the given template with the specified inputs filled in
152        automatically
153        @param template: name of template to render
154        @param inputs: dict of inputs with keynames matching input names in template
155        form 
156        '''
157        logging.debug("Saving current page url (%s) - to keep track of atom editor state" \
158                      %self.pathInfo)
159        session['currentEditor'] = self.pathInfo
160        session.save()
161        logging.debug("Now rendering current template (%s)" %template)
162        html = render("genshi", template)
163        # NB, need html in unicode for for htmlfill.render
164        html = unicode(html, 'utf-8', 'xmlcharrefreplace')
165        for key, val in inputs.items():
166            inputs[key] = str(val)
167
168        return htmlfill.render(html, inputs)
Note: See TracBrowser for help on using the repository browser.