source: MILK/trunk/milk_server/milk_server/controllers/atom_editor/editatom.py @ 5482

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/MILK/trunk/milk_server/milk_server/controllers/atom_editor/editatom.py@5482
Revision 5482, 30.9 KB checked in by aharwood, 11 years ago (diff)

Moved location of redirect following creation of a new atom as otherwise you get an error message displayed (system error 302)

Line 
1'''
2 Class representing pylons controller for the creation and editing of atom
3 data
4 
5 @author: C Byrom, Tessella Sep 2008
6'''
7import logging, traceback, sys, cgi
8from xml.parsers.expat import ExpatError
9from formencode import Invalid
10from genshi.filters import HTMLFormFiller
11from genshi import HTML
12from milk_server.lib.base import *
13from milk_server.models.form import *
14import ndg.common.src.lib.htmlUtilities as utils
15from ndg.common.src.models.Atom import Atom, Person, Link, Category
16from ndg.common.src.models import AtomState
17from ndg.common.src.lib.atomvalidator import ValidationError
18import ndg.common.src.clients.xmldb.abstractxmldbatomclient as ac
19import ndg.common.src.clients.xmldb.eXist.dbconstants as dc
20from ndg.common.src.models.MolesEntity import MolesEntity as ME
21from ndg.common.src.models.vocabtermdata import VocabTermData as VTD
22from ndg.common.src.lib.granulite import granulite
23from editorconstants import *
24from atomeditorcontroller import AtomEditorController
25from milk_server.lib import Utilities
26
27class EditatomController(AtomEditorController):
28    '''
29    Provides the pylons controller for editing NDG Atom documents.
30    '''
31    def upload(self, uri):
32        '''
33        Upload a CSML, CDML or granulite file and store it in the session variable
34        NB, if the uri is specified, we're already dealing with an atom
35        (which this refers to) - so the file is not a granulite - since
36        this is used to create an atom from scratch
37        '''
38        logging.info("Uploading file...")
39        self._setup(uri=uri)
40       
41        granFile = request.POST.get('upload_granulite')
42        csmlOrCdmlFile = request.POST.get('CSMLOrCDML')
43       
44        # check whether we can replace existing atoms
45        replaceAtom = self.inputs.get('replaceAtom')
46       
47        # NB, need to turn from string to boolean - there doesn't seem a reliable
48        # way of doing this using built in methods - so just do simple check
49        if replaceAtom == 'True':
50            replaceAtom = True
51        else:
52            replaceAtom = False
53       
54        # if this is true, then re-extract the inputs from the session data
55        if replaceAtom:
56            if session.get(GRAN_FILE_VALUE):
57                granFile = cgi.FieldStorage()
58                granFile.value = session.get(GRAN_FILE_VALUE)
59                granFile.filename = session.get(GRAN_FILE_NAME)
60                del session[GRAN_FILE_VALUE]
61                del session[GRAN_FILE_NAME]
62               
63            if session.get(CSML_OR_CDML_FILE_VALUE):
64                csmlOrCdmlFile = cgi.FieldStorage()
65                csmlOrCdmlFile.value = session.get(CSML_OR_CDML_FILE_VALUE)
66                csmlOrCdmlFile.filename = session.get(CSML_OR_CDML_FILE_NAME)
67                del session[CSML_OR_CDML_FILE_VALUE]
68                del session[CSML_OR_CDML_FILE_NAME]
69         
70        c.errors = {}
71        try:
72            logging.info("Validating inputs")
73            validator = LoadGranuliteFormSchema()
74            validator.to_python(self.inputs)
75            logging.info("- inputs valid")
76           
77            useCSMLID = True
78            if uri:
79                useCSMLID = False
80
81            if (granFile == '' or granFile == None) and \
82                (csmlOrCdmlFile == '' or csmlOrCdmlFile == None):
83                errorMessage = "Error: could not load file - please try again"
84                logging.error(errorMessage)
85                raise IOError(errorMessage)
86            else:
87                # Prepare the basic data model
88                # NB, if loading a granulite, this will create the displayed atom
89                # with the ID taken from the CSML file, if specified
90                fileContents = None
91                if (granFile is not None and granFile != ''):
92                    fileContents = granFile.value
93                   
94                # use the granulite helper class to add either the full granulite
95                # data or just the CSML/CDML data
96                # NB, we'll be creating the atom in the default local eXist
97                eXistClient = Utilities.getExistClient('local')
98                gran = granulite(fileContents, granuleAtom = c.atom, \
99                                 eXistClient = eXistClient, \
100                                 csmlOrCdmlFile = csmlOrCdmlFile, \
101                                 timeAxis = self.inputs.get('timeAxis'), \
102                                 datasetID = self.inputs.get('granuleDatasetID'), \
103                                 useCSMLID = useCSMLID, \
104                                 replaceAtom = replaceAtom)
105
106                # now process the input file and add any extra required data
107                if uri:
108                    c.atom = gran.processCSMLOrCDMLFile()
109
110                    # save new data - NB, for granulites, this is done as part of the
111                    # processing steps
112                    self.saveAtomToExist(c.atom)
113                else:
114                    try:
115                        c.atom = gran.processGranulite()
116
117                        # Now set up the ndgObject with the created atom's vals
118                        self._setup(uri=c.atom.ndgURI, loadAtom = False)
119                        c.atom.ndgObject = self.ndgObject
120                    except ac.DuplicateError, e:
121                        # we've found an existing atom with the same ID
122                        # - give the users the choice of replacing the contents of this atom
123                        # or just exiting
124                        # - NB, do this via a session variable to act as a flag
125                        # for a javascript command
126                        session[OVERWRITE_GRANULE_FLAG] = e.message
127                       
128                        # store the inputs data for easy retrieval
129                        # - NB, file fields don't behave as text fields - for security
130                        # purposes - so need to store their data as session variables
131                        # for easy retrieval
132                        # - Also, cannot pickle the cgi.FieldStorage object so extract
133                        # picklable data and recreate on the return run
134                        if granFile != '':
135                            session[GRAN_FILE_VALUE] = granFile.value
136                            session[GRAN_FILE_NAME] = granFile.filename
137                        if csmlOrCdmlFile != '':
138                            session[CSML_OR_CDML_FILE_VALUE] = csmlOrCdmlFile.value
139                            session[CSML_OR_CDML_FILE_NAME] = csmlOrCdmlFile.filename
140                       
141                        # need to return to original screen - so clear out variables
142                        c.atom = None
143                        uri = None
144                           
145                # now do redirection - NB, this ensures that current atom contents are
146                # reloaded and displayed
147                logging.info("File data loaded and extracted to atom")
148        except Invalid, e:
149            logging.info(" - inputs invalid")
150            c.errors = e.unpack_errors()
151        except ValidationError, e:
152            logging.info(e)
153            self._unpackErrors(e)
154           
155        except Exception, e:
156            c.errors['WARNING'] = ['Error loading data: the displayed data will not be saved - please fix problem and retry']
157            self._unpackErrors(e)
158        except SystemExit, ee:
159            # NB, some of the CSML libraries just sys.exit on problems - catch errors here
160            c.errors['ERROR'] = ['Problem encountered whilst transforming the CDML data into CSML']
161            self._unpackErrors(ee)
162
163        if c.atom and hasattr(c.atom, 'ndgURI'):
164           
165            if hasattr(self, 'pathInfo'):
166                self.pathInfo = self.pathInfo.replace('upload', 'editAtom')
167
168            # NB, if there are errors, don't redirect otherwise these will get lost
169            if not c.errors:
170                h.redirect_to(h.url_for('edit', uri = c.atom.ndgURI))
171            else:
172                c.atom.contentFile = None
173                return self.edit(c.atom.ndgURI)
174                           
175        elif uri:
176            # something has gone wrong here...
177            return render("genshi", 'error')
178        else:
179            return self.createGranule(**self.inputs)
180
181   
182    def saveAtom(self, uri, saveLevel=0):
183        '''
184        Save the atom contents - NB, validation is done by method decoration
185        - if this fails, the action is reran as a GET with htmlfill auto-populating
186        the fields to keep them as they were before the submission
187        '''
188        logging.info("Saving input atom data")
189        c.errors = {}
190        try:
191            self._setup(uri)
192        except Exception, e:
193            return self._handleError(e)
194       
195        # variable to hold publication state changes
196        newState = None
197       
198        # save atom association changes
199        if int(saveLevel) == self.ADD_ASSOCIATIONS:
200            atomLinks = self.extractAtomAssociations(self.inputs)
201            c.atom.addUniqueRelatedLinks(atomLinks)
202        elif int(saveLevel) == self.REMOVE_ASSOCIATIONS:
203            atomLinks = self.extractAtomAssociations(self.inputs)
204            c.atom.removeRelatedLinks(atomLinks)
205        else:
206            authors = self.extractAuthorDetails(self.inputs)
207            c.atom.addAuthors(authors)
208   
209            onlineRefs = self.extractOnlineReferenceDetails(self.inputs)
210            c.atom.addOnlineReferences(onlineRefs)
211
212            # NB, if params have been specified, or removed, a list will be returned
213            params = self.extractParameterDetails(self.inputs)
214            # NB, the atom type and subtype are added to the categories when the
215            # atom is exported to XML - so don't need to worry about overwriting
216            # them now
217            if params == []:
218                c.atom.parameters = []
219            elif params:
220                c.atom.parameters = []
221                c.atom.addParameters(params)
222           
223            if self.inputs.get('subtype'):
224                c.atom.subtype = self.getLatestTermURLFromDropDownInput( \
225                        self.inputs.get('subtype'))
226                c.atom.subtypeID = c.atom.subtype.split('/')[-1]
227               
228            if self.inputs.get('publication_state'):
229                newState = AtomState.getAtomState(self.inputs['publication_state'])
230
231        logging.info("Validating input")
232        try:
233            g.validator.setAtom(c.atom)
234            g.validator.validateAtom()
235            logging.info("- input valid")
236           
237            # if a change of state has been specified,
238            self.saveAtomToExist(c.atom, newState = newState)
239        except Exception, e:
240            self._unpackErrors(e)
241            logging.info("- input invalid")
242            return self.edit(uri)
243                   
244        # now do redirection - NB, this ensures that current atom contents are
245        # reloaded and displayed
246        h.redirect_to(h.url_for(controller = 'atom_editor/editatom', action='edit', \
247                        uri = c.atom.ndgURI))
248
249
250    def prepareEditForm(self, uri):
251        '''
252        Get everything set up for displaying the edit form
253        @param uri: ndg url for the atom to load in edit mode
254        '''
255        if not c.errors:
256            c.errors = {}
257
258        # NB, can get here directly from saveAtom - if there have been errors
259        # - in this case keep original data
260        if not c.atom:
261            self._setup(uri)
262           
263        c.title= EDIT_TITLE %c.atom.ndgURI
264        c.uri = c.atom.ndgURI
265       
266        c.saveLink = h.url_for('save', saveLevel = self.STANDARD_SAVE, 
267                               uri = c.atom.ndgURI)
268        c.saveAssoc = h.url_for('save', saveLevel = self.REMOVE_ASSOCIATIONS, 
269                                uri = c.atom.ndgURI)
270        c.atom.deploymentsURL = h.url_for('viewAssociatedData', 
271                                          type = VTD.DEPLOYMENT_TERM,
272                                          uri = c.atom.ndgURI)
273        c.atom.dataEntitiesURL = h.url_for('viewAssociatedData', 
274                                           type = VTD.DE_TERM,
275                                           uri = c.atom.ndgURI)
276       
277        # adjust atom type to cope with activity deployment exception
278        atomType = c.atom.atomTypeID
279        if atomType == g.vtd.ACTIVITY_TERM and \
280            c.atom.subtypeID == g.vtd.DEPLOYMENT_TERM:
281            atomType = g.vtd.DEPLOYMENT_TERM
282       
283        c.addEntityLink = h.url_for('list', searchData = '0', \
284                               associatedAtomID = c.atom.ndgURI, \
285                               associatedAtomType = atomType, 
286                               associationType = utils.ENTITY_ASSOCIATION)
287           
288        c.addGranuleLink = h.url_for('list', searchData = '0', \
289                               associatedAtomID = c.atom.ndgURI, \
290                               associatedAtomType = atomType, 
291                               associationType = utils.GRANULE_ASSOCIATION)
292           
293        c.addDeploymentLink = h.url_for('list', searchData = '0', \
294                               associatedAtomID = c.atom.ndgURI, \
295                               associatedAtomType = atomType, 
296                               associationType = utils.DEPLOYMENT_ASSOCIATION)
297
298        # account for special case where we're dealing with deployments
299        listVals = g.vtd.getValidSubTypes(c.atom.atomTypeID)
300        if c.atom.isDeployment():
301            listVals = [g.vtd.TERM_DATA[g.vtd.DEPLOYMENT_TERM]]
302
303        c.subTypes = utils.getVocabTermDataDropdown(listVals, \
304                                        selected=c.atom.subtype)
305       
306        c.states = h.options_for_select(AtomState.selectList, c.atom.state.stateFlag)
307        self.inputs['publication_state'] = c.atom.state.stateFlag
308       
309        self.__setDropDownSelectVal('subtype', c.atom.subtype, listVals)
310        self.addRelatedLinksDropDowns()
311
312
313    def __setDropDownSelectVal(self, name, val, vtds):
314        '''
315        Given a list of vocab terms, with the name of a 'select' tag and the selected
316        value, set the proper value in the inputs dict to allow htmlfill to correctly
317        display the list
318        @param name: name of select element to set the select value of
319        @param val: value of the selected item - NB, this need not be the current vocab
320        term url - but should start with the main stem and end with the termID
321        @param vtds: list of vocab term definition objects
322        '''
323        if not val:
324            return
325        for vtd in vtds:
326            if val.endswith(vtd.termID) and \
327                val.startswith(vtd.vocabURL):
328                self.inputs[name] = utils.getVocabTermDataSelectValue(vtd)
329                return
330           
331
332    def delete(self, uri):
333        '''
334        Delete the atom associated with the specified uri - and return
335        user to the atom home page.  NB, only granule atoms can be deleted
336        at the moment.
337        '''
338        if uri:
339            try:
340                logging.info("Deleting atom, '%s'" %uri)
341                self._setup(uri)
342                eXistClient = Utilities.getExistClient(c.atom.ME.providerID)
343                gran = granulite(None, granuleAtom = c.atom, \
344                                 eXistClient = eXistClient, \
345                                 deleteMode = True)
346   
347                gran.deleteGranuleAndDEReferences()
348                c.deleteResult = "Atom deleted successfully."
349                logging.info("- atom deleted")
350            except Exception, e:
351                logging.error("Problem occured whilst deleting atom: '%s'" %e.message)
352                c.deleteResult = "Warning: a problem occured whilst deleting the atom - this " + \
353                    "may have left the system in an unstable state - please check if the atom, or " + \
354                    "references to the atom still exist"
355
356        return render("genshi", "atom_editor/atom_home")
357       
358   
359    def edit(self, uri):
360        '''
361        Edit the atom with the specified ndg uri
362        '''
363        logging.info("Setting up atom edit template")
364        try:
365            self.prepareEditForm(uri)
366           
367            # NB, there appears to be a bug in htmlfill which automagically
368            # clears out content from textarea - so need to set the content
369            # explicitly for htmlfill to use
370            self.inputs['Content'] = c.atom.Content
371            self.inputs['summary'] = c.atom.summary
372            self.inputs['lineage'] = c.atom.ME.lineage
373            self.inputs['quality'] = c.atom.ME.quality
374            return self.savePageAndRender("atom_editor/atom_editor", **self.inputs)
375       
376        except ExpatError, e:
377            c.xml='XML content is not well formed'
378            c.doc=str(e)
379            logging.error("Error retrieving [%s] - XML content: %s" % (uri, e))
380        except SystemError, e:
381            return self._handleError(e)
382        except Exception, e:
383            errorMessage = traceback.format_exc()
384            c.xml='Unexpected error [%s] viewing [%s]'%(str(e), uri)
385            c.doc=''
386            logging.error(c.xml)
387       
388        response.status_code = 400
389        return render("genshi", 'error')
390
391
392    def addRelatedLinksDropDowns(self):
393        '''
394        Set up the drop down lists required for the selection of online ref links
395        '''
396        # at the very least, we need a simple drop down list with no preselected
397        # values
398        logging.debug("Setting up drop down lists for related links")
399        vtds = g.vtd.getValidTypes(g.vtd.ONLINE_REF_CATEGORY)
400        c.relatedLinkTerms = utils.getVocabTermDataDropdown(vtds)
401
402        # ensure we have set up the correct inputs to allow htmlfill to show
403        # the correct selected value
404        for i, link in enumerate(c.atom.relatedLinks):
405            logging.debug("Adding dropdown for related link, '%s'" %(str(link)))
406            refLabel = Atom.ONLINE_REF_LABEL + "." + str(i) + '.rel'
407           
408            # get the value of the selected list
409            self.__setDropDownSelectVal(refLabel, link.rel, vtds)
410
411        logging.debug("Finished setting up drop down lists")
412
413
414    def extractAuthorDetails(self, inputs):
415        '''
416        Retrieve author data from inputs and set appropriately on Atom, if any
417        found
418        @return: list of Person objects with the author data
419        '''
420        logging.info("Extracting author data from inputs")
421        processedAuthors = []
422        authors = []
423        for key in inputs:
424            keyBits = key.split('.')
425            if len(keyBits) == 3 and keyBits[1] not in processedAuthors:
426               
427                authorType = -1
428                if key.lower().startswith('author'):
429                    authorType = Person.AUTHOR_TYPE
430                elif key.lower().startswith('contributor'):
431                    authorType = Person.CONTRIBUTOR_TYPE
432                elif key.lower().startswith('responsible'):
433                    authorType = Person.RESPONSIBLE_PARTY_TYPE
434                else:
435                    continue
436
437                # NB, adding an empty object here is valid as it will clear out
438                # existing entries, potentially
439                author = Person(personType = authorType)
440                # check if the remove checkbox has been set
441                keyStem = ".".join(keyBits[0:2])
442                if inputs.get(keyStem + ".remove"):
443                    logging.info("Removing author data")
444                else:
445                    author.name = inputs.get(keyStem + '.name') or ""
446                    author.uri = inputs.get(keyStem + '.uri') or ""
447                    author.role = inputs.get(keyStem + '.role') or ""
448                   
449                    logging.info("Adding new author info")
450                    logging.debug("Extracted author (type:'%s', name:'%s', uri:'%s', role:'%s')" \
451                                  %(author.type, author.name, author.uri, author.role))
452                authors.append(author)
453                processedAuthors.append(keyBits[1])
454
455        logging.info("Finished extracting author data")
456        return authors
457
458
459    def extractOnlineReferenceDetails(self, inputs):
460        '''
461        Retrieve online reference data from inputs and set appropriately on Atom, if any
462        found
463        @return: list of Link objects containing the extracted data
464        '''
465        logging.info("Extracting related links data from inputs")
466        processedLinks = []
467        links = []
468
469        for key in inputs:
470            keyBits = key.split('.')
471            if len(keyBits) == 3 and keyBits[1] not in processedLinks:
472               
473                if key.lower().startswith(Atom.ONLINE_REF_LABEL):
474                    link = Link()
475                    keyStem = ".".join(keyBits[0:2])
476                   
477                    if inputs.get(keyStem + ".remove"):
478                        logging.info("Removing online reference data")
479                    else:
480                        # NB, this is in the format vocabURL--termID, so requires further
481                        # processing
482                        link.rel = self.getLatestTermURLFromDropDownInput(inputs.get(keyStem + '.rel'))
483                        link.href = inputs.get(keyStem + '.href') or ""
484                        link.title = inputs.get(keyStem + '.title') or ""
485                       
486                        if not link.hasValue():
487                            continue
488                           
489                        logging.info("Adding new online reference info")
490                        logging.debug("Extracted online reference (href:'%s', title:'%s', rel:'%s')" \
491                                      %(link.href, link.title, link.rel))
492                        links.append(link)
493
494                    processedLinks.append(keyBits[1])
495                else:
496                    continue
497
498        logging.info("Finished extracting links data")
499        return links
500
501
502    def extractParameterDetails(self, inputs):
503        '''
504        Retrieve parameters data from inputs and set appropriately on Atom, if any
505        found
506        @return: list of parameter data in triple string format - i.e.
507        of format, 'label | scheme | term'
508        If no parameters are found, return None.  NB, if all params have been
509        removed, return []
510        '''
511        logging.info("Extracting parameters data from inputs")
512        processedParameters = []
513        parameters = []
514
515        emptyParam = " |  | "
516        for key in inputs:
517            keyBits = key.split('.')
518            if len(keyBits) == 3 and keyBits[1] not in processedParameters:
519               
520                if key.lower().startswith(Atom.PARAMETER_LABEL):
521                    keyStem = ".".join(keyBits[0:2])
522                   
523                    if inputs.get(keyStem + ".remove"):
524                        logging.info("Removing parameters data")
525                    else:
526                        parameter = inputs.get(keyStem + '.label') or ""
527                        parameter += " | " + inputs.get(keyStem + '.scheme') or ""
528                        parameter += " | " + inputs.get(keyStem + '.term') or ""
529
530                        if parameter == emptyParam:
531                            continue
532                       
533                        logging.info("Adding new parameter info: %s" %parameter)
534                        parameters.append(parameter)
535
536                    processedParameters.append(keyBits[1])
537                else:
538                    continue
539
540        if not processedParameters:
541            return None
542       
543        logging.info("Finished extracting parameters data")
544        return parameters
545
546
547    def extractAtomAssociations(self, inputs):
548        '''
549        Retrieve atom data from inputs and create related links pointing to
550        this data
551        @return: list of Links representing the related atoms
552        '''
553        logging.info("Extracting related atom ID data from inputs")
554        atoms = []
555        processedAtoms = []
556
557        for key in inputs:
558            if key.lower().startswith(Atom.ATOM_REF_LABEL):
559                (x, href, title, rel) = key.split(Atom.DELIMITER)
560                # NB, we handle removes by effectively ignoring them later on
561                if href not in processedAtoms:
562                    processedAtoms.append(href)
563
564                    link = Link()
565                    link.href = href or ""
566                    link.title = title or ""
567                    link.rel = rel or ""
568                   
569                    # adjust href to point to the browse, not the edit version
570                    link.href = link.href.replace('editAtom', 'view')
571                    link.href = link.href.replace(g.server, VTD.BROWSE_SERVER_URL)
572                   
573                    logging.debug("Extracted atom info (href:'%s', title:'%s', rel:'%s')" \
574                                  %(link.href, link.title, link.rel))
575                    atoms.append(link)
576            else:
577                continue
578
579        logging.info("Finished extracting atoms data")
580        return atoms
581               
582
583    def getLatestTermURLFromDropDownInput(self, inputVal):
584        '''
585        Term ID and vocabURL are specified in the drop down menus
586        - using the input from this, return the lastest full href to the
587        term ID
588        '''
589        termData = inputVal.split('--')
590        return g.vtd.getCurrentVocabURI(termData[0]) + \
591                        "/" + termData[1]
592
593
594    def saveAtomToExist(self, atom, newState = None):
595        '''
596        Save the specified atom in eXist
597        @param atom: atom object to save to eXist
598        @keyword newState:  AtomState publication state to move the atom to, default: None
599        - use the current atom state
600        @return atom: atom object saved in eXist
601        '''
602        logging.info("Saving changes to eXist")
603        eXist = Utilities.getExistClient(atom.ME.providerID)
604       
605        if newState and newState != atom.state:
606            createdAtom = eXist.changeAtomPublicationState(atom, newState)
607        else:
608            createdAtom = eXist.createAtom(atom)
609           
610        # update references to the atom, if its title has changed
611        if atom.oldTitle != atom.title:
612            self.__updateAtomReferences(atom, eXist)
613           
614        logging.info("Changes successfully saved to eXist")
615        return createdAtom
616
617
618    def __updateAtomReferences(self, atom, eXist):
619        '''
620        If an atom title changes, update any references to it elsewhere - since
621        this title is used in the link 'title' attribute
622        @param atom: Atom whose references need to be updated
623        @param eXist: AtomClient for eXist DB
624        '''
625        logging.info("- updating references to atom with changed title")
626        atoms = []
627        if atom.atomTypeID == VTD.GRANULE_TERM or \
628            (atom.atomTypeID == VTD.ACTIVITY_TERM and \
629            atom.subtypeID == VTD.DEPLOYMENT_TERM):
630            logging.debug("- retrieving references in data entities")
631            atom.lookupAssociatedData(VTD.DE_TERM, eXist,
632                                      lookupIndirectReferences = True)
633            for de in atom.dataEntities:
634                doc = eXist.buildAndRunQuery('atom', 
635                                             dc.ATOM_COLLECTION_PATH, 
636                                             "", 
637                                             de.rel)
638                atoms.append(Atom(xmlString=str(doc[0])))
639
640        elif atom.atomTypeID == VTD.DE_TERM:
641            # DEs are never referenced by other atoms - just keep this check
642            # to make an easier catch all 'else' for the deployments data
643            logging.debug("Atom is a data entity - so has no references elsewhere to update")
644        else:
645            logging.debug("- retrieving references in deployments")
646            atom.lookupAssociatedData(VTD.DEPLOYMENT_TERM, eXist,
647                                      lookupIndirectReferences = True)
648
649            for dep in atom.deployments:
650                doc = eXist.buildAndRunQuery('atom', 
651                                             dc.ATOM_COLLECTION_PATH, 
652                                             dep.providerID, 
653                                             dep.id)
654                atoms.append(Atom(xmlString=str(doc[0])))
655
656        logging.debug("- references retrieved - now updating")
657        for refAtom in atoms:
658            for rel in refAtom.relatedLinks:
659                if rel.title == atom.oldTitle:
660                    rel.title = atom.title
661       
662            eXist.createAtom(refAtom)
663        logging.info("- references updated")
664       
665   
666    def create(self, saveData = None, **inputs):
667        '''
668        Create a new atom
669        '''
670        self._setup()
671       
672        url = None
673       
674        if saveData:
675            logging.info("Validating input")
676            try:
677                validator = CreateAtomFormSchema()
678                validator.to_python(self.inputs)
679                logging.info("- input valid")
680               
681                logging.info("Creating basic atom")
682                atomTypeID = self.inputs.get('atomTypeID').split('--')[1]
683                self.inputs['atomTypeID'] = atomTypeID
684   
685                # activity deployments should have subtype deployment specified automatically
686                if atomTypeID == g.vtd.ACTIVITY_DEPLOYMENT_TERM:
687                    self.inputs['subtypeID'] = g.vtd.DEPLOYMENT_TERM
688                    self.inputs['atomTypeID'] = g.vtd.ACTIVITY_TERM
689                   
690                self.inputs['providerID'] = self.inputs.get('providerID').split('--')[1]
691                atom = self.saveAtomToExist(Atom(**dict(self.inputs)))
692                url = h.url_for('edit', uri = atom.ndgURI, saveData=None)
693
694            except Invalid, e:
695                c.errors = e.unpack_errors()
696            except Exception, e:
697                c.xml = 'System Error: %s' %str(e)
698                return render("genshi", 'error')
699
700            # NB, the redirect throws an exception, so be careful not to catch it
701            if url:
702               h.redirect_to(url)               
703           
704        logging.info("Setting up atom create template")
705        c.title = CREATE_ATOM_TITLE
706       
707        # set up the drop down content - NB, add special case, 'deployment activity'
708        # - this is just a specialised activity - i.e. with subtype preset
709        c.atomTypes = utils.getVocabTermDataDropdown(g.vtd.getValidTypes(g.vtd.ATOM_CATEGORY))
710        c.providerIDs = utils.getVocabTermDataDropdown(g.vtd.getValidTypes(g.vtd.PROVIDER_CATEGORY))
711
712        try:
713            return self.savePageAndRender('atom_editor/atom_creator', **self.inputs)
714
715        except Exception, e:
716            return self._handleError(e)
717
718   
719    def createGranule(self, **inputs):
720        '''
721        Create a new atom from a granulite file
722        '''
723        self._setup()
724        logging.info("Setting up new atom from granulite template")
725        c.title='Create new data granule atom - from a granulite file'
726
727        if not hasattr(c, 'errors'):
728            c.errors = {}
729        try:
730            return self.savePageAndRender('atom_editor/atom_granulator', **inputs)
731
732        except Exception, e:
733            return self._handleError(e)
Note: See TracBrowser for help on using the repository browser.