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

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

Adjust atom links when in editor mode to point to the editor instance

  • and correct these when saving the data so that the links actually

point to the browse service + turn of granule delete function when not
in edit mode + remove duplicated inclusion of badc icon + tidy up
config file.

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