class PlominoDocument(CatalogAware, CMFBTreeFolder, Contained): """ These represent the contents in a Plomino database. A document contains *items* that may or may not correspond to fields on one or more forms. """ security = ClassSecurityInfo() implements(interfaces.IPlominoDocument, IAttributeAnnotatable) portal_type = "PlominoDocument" meta_type = "PlominoDocument" security.declarePublic('__init__') def __init__(self, id): """ Initialization """ CMFBTreeFolder.__init__(self, id) self.id = id self.items = PersistentDict() self.plomino_modification_time = DateTime().toZone('UTC') security.declarePublic('checkBeforeOpenDocument') def checkBeforeOpenDocument(self): """ Check read permission and open view. .. NOTE:: if ``READ_PERMISSION`` is set on the ``view`` action itself, it causes an error ('maximum recursion depth exceeded') if user hasn't permission. """ if self.isReader(): return self.OpenDocument() else: raise Unauthorized, "You cannot read this content" def doc_path(self): return self.getPhysicalPath() def doc_url(self): """ return valid and nice url: - hide plomino_documents - use physicalPathToURL if REQUEST available """ path = self.doc_path() short_path = [p for p in path if p != "plomino_documents"] if hasattr(self, "REQUEST"): return self.REQUEST.physicalPathToURL(short_path) else: return "/".join(short_path) security.declarePublic('setItem') def setItem(self, name, value): """ """ items = self.items if type(value) == type(''): db = self.getParentDatabase() translation_service = getToolByName(db, 'translation_service') value = translation_service.asunicodetype(value) items[name] = value self.items = items self.plomino_modification_time = DateTime().toZone('UTC') security.declarePublic('getItem') def getItem(self, name, default=''): """ """ if (self.items.has_key(name)): return deepcopy(self.items[name]) else: return default security.declarePublic('hasItem') def hasItem(self, name): """ """ return self.items.has_key(name) security.declarePublic('removeItem') def removeItem(self, name): """ """ if (self.items.has_key(name)): items = self.items del items[name] self.items = items security.declarePublic('getItems') def getItems(self): """ """ return self.items.keys() security.declarePublic('getItemClassname') def getItemClassname(self, name): """ """ return self.getItem(name).__class__.__name__ security.declarePublic('getLastModified') def getLastModified(self, asString=False): """ """ if not hasattr(self, 'plomino_modification_time'): self.plomino_modification_time = self.bobobase_modification_time( ).toZone('UTC') if asString: return str(self.plomino_modification_time) else: return self.plomino_modification_time security.declarePublic('getRenderedItem') def getRenderedItem(self, itemname, form=None, formid=None, convertattachments=False): """ Return the item rendered according to the corresponding field. The used form can be, in order of precedence: - passed as the `form` parameter, - specified with the `formid` parameter and looked up, - looked up from the document. If no form or field is found, return the empty string. If `convertattachments` is True, then we assume that field attachments are text and append them to the rendered value. """ db = self.getParentDatabase() result = '' if not form: if formid: form = db.getForm(formid) else: form = self.getForm() if form: field = form.getFormField(itemname) if field: result = field.getFieldRender(form, self, False) if (field.getFieldType() == 'ATTACHMENT' and convertattachments): result += ' ' + db.getIndex().convertFileToText( self, itemname).decode('utf-8') result = result.encode('utf-8') return result security.declarePublic('tojson') def tojson(self, REQUEST=None, item=None, formid=None, rendered=False): """return item value as JSON (return all items if item=None) """ if not self.isReader(): raise Unauthorized, "You cannot read this content" datatables_format = False if REQUEST: REQUEST.RESPONSE.setHeader('content-type', 'application/json; charset=utf-8') item = REQUEST.get('item', item) formid = REQUEST.get('formid', formid) rendered_str = REQUEST.get('rendered', None) if rendered_str: rendered = True datatables_format_str = REQUEST.get('datatables', None) if datatables_format_str: datatables_format = True if not item: return json.dumps(self.items.data) if not formid: form = self.getForm() else: form = self.getParentDatabase().getForm(formid) if form: field = form.getFormField(item) if field: if field.getFieldType() == 'DATAGRID': adapt = field.getSettings() fieldvalue = adapt.getFieldValue(form, self, False, False, REQUEST) fieldvalue = adapt.rows(fieldvalue, rendered=rendered) if datatables_format: fieldvalue = { 'iTotalRecords': len(fieldvalue), 'aaData': fieldvalue } else: if rendered: fieldvalue = self.getRenderedItem(item, form) else: adapt = field.getSettings() fieldvalue = adapt.getFieldValue( form, self, False, False, REQUEST) else: fieldvalue = self.getItem(item) else: fieldvalue = self.getItem(item) return json.dumps(fieldvalue) security.declarePublic('computeItem') def computeItem(self, itemname, form=None, formid=None, store=True, report=True): """ return the item value according the formula of the field defined in the given form (use default doc form if None) and store the value in the doc (if store=True) """ result = None db = self.getParentDatabase() if not form: if not formid: form = self.getForm() else: form = db.getForm(formid) if form: result = form.computeFieldValue(itemname, self, report=report) if store: self.setItem(itemname, result) return result security.declarePublic('getPlominoReaders') def getPlominoReaders(self): """ """ if self.hasItem('Plomino_Readers'): return asList(self.Plomino_Readers) else: return ['*'] security.declarePublic('isReader') def isReader(self): """ """ return self.getParentDatabase().isCurrentUserReader(self) security.declarePublic('isAuthor') def isAuthor(self): """ """ return self.getParentDatabase().isCurrentUserAuthor(self) security.declareProtected(REMOVE_PERMISSION, 'delete') def delete(self, REQUEST=None): """delete the current doc """ db = self.getParentDatabase() db.deleteDocument(self) if not REQUEST is None: return_url = REQUEST.get('returnurl') REQUEST.RESPONSE.redirect(return_url) security.declareProtected(EDIT_PERMISSION, 'validation_errors') def validation_errors(self, REQUEST): """check submitted values """ db = self.getParentDatabase() form = db.getForm(REQUEST.get('Form')) errors = form.validateInputs(REQUEST, doc=self) if len(errors) > 0: return self.errors_json(errors=json.dumps({ 'success': False, 'errors': errors })) else: return self.errors_json(errors=json.dumps({'success': True})) security.declareProtected(EDIT_PERMISSION, 'saveDocument') def saveDocument(self, REQUEST, creation=False): """save a document using the form submitted content """ db = self.getParentDatabase() form = db.getForm(REQUEST.get('Form')) errors = form.validateInputs(REQUEST, doc=self) if len(errors) > 0: return form.notifyErrors(errors) self.setItem('Form', form.getFormName()) # process editable fields (we read the submitted value in the request) form.readInputs(self, REQUEST, process_attachments=True) # refresh computed values, run onSave, reindex self.save(form, creation) redirect = REQUEST.get('plominoredirecturl') if not redirect: redirect = self.getItem("plominoredirecturl") if not redirect: redirect = self.absolute_url() REQUEST.RESPONSE.redirect(redirect) security.declareProtected(EDIT_PERMISSION, 'refresh') def refresh(self, form=None): """ re-compute fields and re-index document (onSave event is not called, and authors are not updated """ self.save(form, creation=False, refresh_index=True, asAuthor=False, onSaveEvent=False) security.declareProtected(EDIT_PERMISSION, 'save') def save(self, form=None, creation=False, refresh_index=True, asAuthor=True, onSaveEvent=True): """refresh values according form, and reindex the document """ # we process computed fields (refresh the value) if form is None: form = self.getForm() else: self.setItem('Form', form.getFormName()) db = self.getParentDatabase() if form: for f in form.getFormFields(includesubforms=True, doc=self, applyhidewhen=False): mode = f.getFieldMode() fieldname = f.id if mode in ["COMPUTED", "COMPUTEDONSAVE" ] or (mode == "CREATION" and creation): result = form.computeFieldValue(fieldname, self) self.setItem(fieldname, result) else: # computed for display field are not stored pass # compute the document title title_formula = form.getDocumentTitle() if title_formula: # Use the formula if we have one try: title = self.runFormulaScript("form_" + form.id + "_title", self, form.DocumentTitle) if title != self.Title(): self.setTitle(title) except PlominoScriptException, e: e.reportError('Title formula failed') elif creation: # If we have no formula and we're creating, use Form's title title = form.Title() if title != self.Title(): # We may be calling save with 'creation=True' on # existing documents, in which case we may already have # a title. self.setTitle(title) # update the document id if creation and form.getDocumentId(): new_id = self.generateNewId() if new_id: transaction.savepoint(optimistic=True) db.documents.manage_renameObject(self.id, new_id) # update the Plomino_Authors field with the current user name if asAuthor: authors = self.getItem('Plomino_Authors') name = db.getCurrentUser().getUserName() if authors == '': authors = [] authors.append(name) elif name in authors: pass else: authors.append(name) self.setItem('Plomino_Authors', authors) # execute the onSaveDocument code of the form if form and onSaveEvent: try: result = self.runFormulaScript("form_" + form.id + "_onsave", self, form.onSaveDocument) if result and hasattr(self, 'REQUEST'): self.REQUEST.set('plominoredirecturl', result) except PlominoScriptException, e: if hasattr(self, 'REQUEST'): e.reportError( 'Document has been saved but onSave event failed.') doc_path = self.REQUEST.physicalPathToURL(self.doc_path()) self.REQUEST.RESPONSE.redirect(doc_path)
class AdmUtilEventCrossbar(Supernode): """Implementation of local EventCrossbar Utility""" implements(IAdmUtilEventCrossbar) lastEventCrossbar = "no signal since start" def __init__(self): Supernode.__init__(self) self.ikRevision = __version__ self.inpEQueues = PersistentDict() self.outEQueues = PersistentDict() def receiveEventCrossbar(self, request, str_time, mode=None): """receive eventcrossbar signal """ self.lastEventCrossbar = str_time dcore = IWriteZopeDublinCore(self) dcore.modified = datetime.now(berlinTZ) def getEventCrossbarTime(self): """get last eventcrossbar timestamp """ try: retVal = self.lastEventCrossbar except NameError: self.__setattr__("lastEventCrossbar", "not set") retVal = self.lastEventCrossbar return retVal def fillDotFile(self, dotFile, mode=None): """generate the dot file """ my_catalog = zapi.getUtility(ICatalog) objIdSet = set() objSet = set() eventSet = set() for (oid, oobj) in self.items(): objIdSet.add(oid) for objId in self.inpEQueues: objIdSet.add(objId) for objId in self.outEQueues: objIdSet.add(objId) for objId in objIdSet: for result in my_catalog.searchResults(oid_index=objId): if IAdmUtilEvent.providedBy(result): eventSet.add(result) elif IEventLogic.providedBy(result): objSet.add(result) elif IEventLogic.providedBy(result): objSet.add(result) elif IComponent.providedBy(result): if result.isConnectedToEvent(): objSet.add(result) else: pass print >> dotFile, '// GraphViz DOT-File' print >> dotFile, 'digraph "%s" {' % (zapi.getRoot(self).__name__) if mode and mode.lower() == "fview": print >> dotFile, '\tgraph [bgcolor="#E5FFF9", dpi="100.0"];' else: print >> dotFile, '\tgraph [bgcolor="#E5FFF9", size="6.2,5.2",' +\ ' splines="true", ratio = "auto", dpi="100.0"];' print >> dotFile, '\tnode [fontname = "Helvetica",fontsize = 10];' print >> dotFile, '\tedge [style = "setlinewidth(2)", color = black];' print >> dotFile, '\trankdir = LR;' print >> dotFile, '\t// objects ----------------------------------' for obj in objSet: objGraphvizDot = IGenGraphvizDot(obj) objGraphvizDot.traverse4DotGenerator(dotFile, level=1, comments=True, signalsOutput=True, recursive=False) #print "-" * 80 #uidutil = zapi.getUtility(IIntIds) #print >> dotFile, '\t// locations ----------------------------------' #for (oid, oobj) in uidutil.items(): #if ILocation.providedBy(oobj.object): #print "Location: ", oobj.object.ikName #print >> dotFile, \ #'\tsubgraph "cluster_location" { color=blue; label="location"};' ##elif IRoom.providedBy(oobj.object): ##print "Room: ", oobj.object.ikName ##elif ILocation.providedBy(oobj.object): ##print "Location: ", oobj.object.ikName #print "-" * 80 print >> dotFile, '\t// events ----------------------------------' for event in eventSet: eventGraphvizDot = IGenGraphvizDot(event) eventGraphvizDot.traverse4DotGenerator(dotFile, level=1, comments=True) for obj in objSet: allInpNamesDict = obj.getAllInpEventNames() allOutNamesDict = obj.getAllOutEventNames() for inpName in allInpNamesDict.keys(): for iObj in allInpNamesDict[inpName]: print >> dotFile, '\t "%s"-> "%s":"%s"' % ( iObj, obj.objectID, inpName) for outName in allOutNamesDict.keys(): for iObj in allOutNamesDict[outName]: print >> dotFile, '\t "%s":"%s"-> "%s"' % (obj.objectID, outName, iObj) print >> dotFile, '}' dotFile.flush() def getIMGFile(self, imgtype, mode=None): """get dot file and convert to png """ dotFileName = '/tmp/dotFile_%s.dot' % os.getpid() outFileName = '/tmp/dotFile_%s.out' % os.getpid() dotFile = open(dotFileName, 'w') self.fillDotFile(dotFile, mode) dotFile.close() os.system("dot -T%s -o %s %s" % (imgtype, outFileName, dotFileName)) pic = open(outFileName, "r") picMem = pic.read() pic.close() return picMem def getCmapxText(self, root_obj): """get dot file and convert to client side image map """ its = root_obj.items() dotFileName = '/tmp/dotFile_%s.dot' % os.getpid() outFileName = '/tmp/dotFile_%s.out' % os.getpid() dotFile = open(dotFileName, 'w') self.fillDotFile(its, dotFile) dotFile.close() os.system("%s -Tcmapx -o %s %s" % (self.graphviz_type, outFileName, dotFileName)) mymap = open(outFileName, "r") mapMem = mymap.read() mymap.close() return mapMem def makeNewObjQueue(self, senderObj): """ will create a new input and output queue for this sender object """ objId = senderObj.getObjectId() if not self.inpEQueues.has_key(objId): self.inpEQueues[objId] = Queue() if not self.outEQueues.has_key(objId): self.outEQueues[objId] = Queue() return True def destroyObjQueue(self, senderObj): """ will destroy the input and output queue for this sender object """ objId = senderObj.getObjectId() if self.inpEQueues.has_key(objId): del self.inpEQueues[objId] if self.outEQueues.has_key(objId): del self.outEQueues[objId] return True def injectEventFromObj(self, senderObj, event): """ will inject an event from the sender object into the accordant queue """ objId = senderObj.getObjectId() if self.inpEQueues.has_key(objId): self.inpEQueues[objId].put(event) return True return False def processOutEQueues(self): for objId in self.outEQueues: outQueue = self.outEQueues[objId] while len(outQueue) > 0: my_catalog = zapi.getUtility(ICatalog) foundObj = False for result in my_catalog.searchResults(oid_index=objId): event = iter(outQueue).next() # don't delete if result.injectInpEQueue(event): foundObj = True outQueue.pull() # now delete #if not foundObj: #print "delete trash" #outQueue.pull() # delete trash def processEvents(self): pass def processInpEQueues(self): my_catalog = zapi.getUtility(ICatalog) for senderOid in self.inpEQueues: inpQueue = self.inpEQueues[senderOid] while len(inpQueue) > 0: inpEvent = inpQueue.pull() processed = False for eventObj in self.values(): if IAdmUtilEvent.providedBy(eventObj): if (senderOid in eventObj.inpObjects) and \ (eventObj.objectID == inpEvent.oidEventObject): for receiverOid in eventObj.outObjects: for receiverObj in my_catalog.searchResults(\ oid_index=receiverOid): processed = True receiverObj.injectInpEQueue(inpEvent) if not processed: for oid in self.outEQueues: for receiverObj in my_catalog.searchResults(\ oid_index=oid): if (inpEvent.oidEventObject in \ receiverObj.getAllInpEventObjs()): processed = True receiverObj.injectInpEQueue(inpEvent) if not processed: inpEvent.stopit(self) def tickerEvent(self): ## debug if queue not empty #for qid in self.inpEQueues: #if len(self.inpEQueues[qid]) > 0: #logger.info("tickerEvent (n:%s, n(i):%s, n(o):%s)" % \ #(qid, #len(self.inpEQueues[qid]), #len(self.outEQueues[qid]) #)) self.processOutEQueues() self.processEvents() self.processInpEQueues() def logIntoEvent(self, oidEventObject, logEntry): if self.has_key(oidEventObject): eventObject = self[oidEventObject] if eventObject.logAllEvents: newEntry = Entry(logEntry, eventObject, level=u"info") eventObject.history.append(newEntry) eventObject._p_changed = True def getEvent(self, oidEventObject): if self.has_key(oidEventObject): return self[oidEventObject] else: return None def debugEventHistory(self, eventObject=None): if eventObject is not None: my_catalog = zapi.getUtility(ICatalog) print "debugEventHistory:" print "-" * 40 for entry in eventObject.transmissionHistory: for obj in my_catalog.searchResults(oid_index=entry): print " -> ", obj.getDcTitle() print "-" * 40
class OrderedContainer(Persistent, Contained): """ `OrderedContainer` maintains entries' order as added and moved. >>> oc = OrderedContainer() >>> int(IOrderedContainer.providedBy(oc)) 1 >>> len(oc) 0 """ implements(IOrderedContainer) def __init__(self): self._data = PersistentDict() self._order = PersistentList() def keys(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.keys() ['foo'] >>> oc['baz'] = 'quux' >>> oc.keys() ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 """ return self._order[:] def __iter__(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc['baz'] = 'quux' >>> [i for i in oc] ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 """ return iter(self.keys()) def __getitem__(self, key): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc['foo'] 'bar' """ return self._data[key] def get(self, key, default=None): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc.get('foo') 'bar' >>> oc.get('funky', 'No chance, dude.') 'No chance, dude.' """ return self._data.get(key, default) def values(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.values() ['bar'] >>> oc['baz'] = 'quux' >>> oc.values() ['bar', 'quux'] >>> int(len(oc._order) == len(oc._data)) 1 """ return [self._data[i] for i in self._order] def __len__(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> int(len(oc) == 0) 1 >>> oc['foo'] = 'bar' >>> int(len(oc) == 1) 1 """ return len(self._data) def items(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.items() [('foo', 'bar')] >>> oc['baz'] = 'quux' >>> oc.items() [('foo', 'bar'), ('baz', 'quux')] >>> int(len(oc._order) == len(oc._data)) 1 """ return [(i, self._data[i]) for i in self._order] def __contains__(self, key): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> int('foo' in oc) 1 >>> int('quux' in oc) 0 """ return self._data.has_key(key) has_key = __contains__ def __setitem__(self, key, object): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc._order ['foo'] >>> oc['baz'] = 'quux' >>> oc._order ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 >>> oc['foo'] = 'baz' Traceback (most recent call last): ... KeyError: u'foo' >>> oc._order ['foo', 'baz'] """ existed = self._data.has_key(key) bad = False if isinstance(key, StringTypes): try: unicode(key) except UnicodeError: bad = True else: bad = True if bad: raise TypeError("'%s' is invalid, the key must be an " "ascii or unicode string" % key) if len(key) == 0: raise ValueError("The key cannot be an empty string") # We have to first update the order, so that the item is available, # otherwise most API functions will lie about their available values # when an event subscriber tries to do something with the container. if not existed: self._order.append(key) # This function creates a lot of events that other code listens to. try: setitem(self, self._data.__setitem__, key, object) except Exception, e: if not existed: self._order.remove(key) raise e return key
class PlominoDocument(CatalogAware, CMFBTreeFolder, Contained): """ These represent the contents in a Plomino database. A document contains *items*. An item may or may not correspond to fields on one or more forms. They may be manipulated by Formulas. """ security = ClassSecurityInfo() implements(interfaces.IPlominoDocument, IAttributeAnnotatable) portal_type = "PlominoDocument" meta_type = "PlominoDocument" security.declarePublic('__init__') def __init__(self, id): """ Initialization """ CMFBTreeFolder.__init__(self, id) self.id = id self.items = PersistentDict() self.plomino_modification_time = DateTime().toZone(TIMEZONE) security.declarePublic('checkBeforeOpenDocument') def checkBeforeOpenDocument(self): """ Check read permission and open view. .. NOTE:: if ``READ_PERMISSION`` is set on the ``view`` action itself, it causes an error ('maximum recursion depth exceeded') if user hasn't permission. """ if self.isReader(): return self.OpenDocument() else: raise Unauthorized, "You cannot read this content" def doc_path(self): return self.getPhysicalPath() def doc_url(self): """ Return valid and nice url: - hide plomino_documents - use physicalPathToURL if REQUEST available """ path = self.doc_path() short_path = [p for p in path if p != "plomino_documents"] if hasattr(self, "REQUEST"): return self.REQUEST.physicalPathToURL(short_path) else: return "/".join(short_path) security.declarePublic('setItem') def setItem(self, name, value): """ Set item on document, converting str to unicode. """ items = self.items if isinstance(value, str): db = self.getParentDatabase() translation_service = getToolByName(db, 'translation_service') value = translation_service.asunicodetype(value) items[name] = value self.items = items self.plomino_modification_time = DateTime().toZone(TIMEZONE) security.declarePublic('getItem') def getItem(self, name, default=''): """ Get item from document. """ if self.items.has_key(name): return deepcopy(self.items[name]) else: return default security.declarePublic('hasItem') def hasItem(self, name): """ Check if doc has item 'name'. """ return self.items.has_key(name) security.declarePublic('removeItem') def removeItem(self, name): """ Delete item 'name', if it exists. """ if self.items.has_key(name): items = self.items del items[name] self.items = items security.declarePublic('getItems') def getItems(self): """ Return all item names. """ return self.items.keys() security.declarePublic('getItemClassname') def getItemClassname(self, name): """ Return class name of the item. """ return self.getItem(name).__class__.__name__ security.declarePublic('getLastModified') def getLastModified(self, asString=False): """ Return last modified date, setting it if absent. """ if not hasattr(self, 'plomino_modification_time'): self.plomino_modification_time = self.bobobase_modification_time( ).toZone(TIMEZONE) if asString: return DateToString(self.plomino_modification_time, db=self.getParentDatabase()) else: return self.plomino_modification_time security.declarePublic('getRenderedItem') def getRenderedItem(self, itemname, form=None, formid=None, convertattachments=False): """ Return the item rendered according to the corresponding field. The form used can be, in order of precedence: - passed as the `form` parameter, - specified with the `formid` parameter and looked up, - looked up from the document. If no form or field is found, return the empty string. If `convertattachments` is True, then we assume that field attachments are text and append them to the rendered value. """ db = self.getParentDatabase() result = '' if not form: if formid: form = db.getForm(formid) else: form = self.getForm() if form: field = form.getFormField(itemname) if field: result = field.getFieldRender(form, self, False) if (field.getFieldType() == 'ATTACHMENT' and convertattachments): result += ' ' + db.getIndex().convertFileToText( self, itemname).decode('utf-8') result = result.encode('utf-8') return result security.declarePublic('tojson') def tojson(self, REQUEST=None, item=None, formid=None, rendered=False, lastmodified=None): """ Return item value as JSON. Return all items if `item=None`. Values on the REQUEST overrides parameters. If the requested item corresponds to a field on the found form, the field value is returned. If not, it falls back to a plain item lookup on the document. `formid="None"` specifies plain item lookup. """ # TODO: Don't always return the entire dataset: allow batching. if not self.isReader(): raise Unauthorized, "You cannot read this content" datatables_format = False if REQUEST: REQUEST.RESPONSE.setHeader('content-type', 'application/json; charset=utf-8') item = REQUEST.get('item', item) formid = REQUEST.get('formid', formid) lastmodified = REQUEST.get('lastmodified', lastmodified) rendered_str = REQUEST.get('rendered', None) if rendered_str: rendered = True datatables_format_str = REQUEST.get('datatables', None) if datatables_format_str: datatables_format = True if item: if formid == "None": form = None elif formid: form = self.getParentDatabase().getForm(formid) else: form = self.getForm() if form: field = form.getFormField(item) if field: if field.getFieldType() == 'DATAGRID': adapt = field.getSettings() fieldvalue = adapt.getFieldValue(form, doc=self, request=REQUEST) fieldvalue = adapt.rows(fieldvalue, rendered=rendered) else: if rendered: fieldvalue = self.getRenderedItem(item, form) else: adapt = field.getSettings() fieldvalue = adapt.getFieldValue(form, doc=self, request=REQUEST) else: _logger.info("Failed to find %s on %s, " "fallback to getItem." % (item, form.id)) fieldvalue = self.getItem(item) else: fieldvalue = self.getItem(item) data = fieldvalue else: data = self.items.data if datatables_format: data = { 'iTotalRecords': len(data), 'iTotalDisplayRecords': len(data), 'aaData': data } if lastmodified: data = {'lastmodified': self.getLastModified(), 'data': data} return json.dumps(data) security.declarePublic('computeItem') def computeItem(self, itemname, form=None, formid=None, store=True, report=True): """ Return the value of named item according to the formula - of the field defined in the given form (default), - or the named `formid`, - or use the default doc form if no form found. Store the value in the doc (if `store=True`). (Pass `report` to `PlominoForm.computeFieldValue`.) """ result = None if not form: if not formid: form = self.getForm() else: db = self.getParentDatabase() form = db.getForm(formid) if form: result = form.computeFieldValue(itemname, self, report=report) if store: # So this is a way to store the value of a DISPLAY field .. self.setItem(itemname, result) return result security.declarePublic('getPlominoReaders') def getPlominoReaders(self): """ Return list of readers; if none set, everyone can read. """ if self.hasItem('Plomino_Readers'): return asList(self.getItem('Plomino_Readers')) else: return ['*'] security.declarePublic('isReader') def isReader(self): """ """ return self.getParentDatabase().isCurrentUserReader(self) security.declarePublic('isAuthor') def isAuthor(self): """ """ return self.getParentDatabase().isCurrentUserAuthor(self) security.declareProtected(REMOVE_PERMISSION, 'delete') def delete(self, REQUEST=None): """ Delete the current doc; redirect to `returnurl` if available. """ db = self.getParentDatabase() db.deleteDocument(self) if REQUEST: return_url = REQUEST.get('returnurl') if not return_url: return_url = db.absolute_url() REQUEST.RESPONSE.redirect(return_url) security.declareProtected(EDIT_PERMISSION, 'validation_errors') def validation_errors(self, REQUEST): """ Check submitted values. """ db = self.getParentDatabase() form = db.getForm(REQUEST.get('Form')) errors = form.validateInputs(REQUEST, doc=self) if errors: return self.errors_json(errors=json.dumps({ 'success': False, 'errors': errors })) else: return self.errors_json(errors=json.dumps({'success': True})) security.declareProtected(EDIT_PERMISSION, 'saveDocument') def saveDocument(self, REQUEST, creation=False): """ Save a document using the form submitted content """ db = self.getParentDatabase() form = db.getForm(REQUEST.get('Form')) errors = form.validateInputs(REQUEST, doc=self) # execute the beforeSave code of the form error = None try: error = self.runFormulaScript( SCRIPT_ID_DELIMITER.join(['form', form.id, 'beforesave']), self, form.getBeforeSaveDocument) except PlominoScriptException, e: e.reportError('Form submitted, but beforeSave formula failed') if error: errors.append(error) # if errors, stop here, and notify errors to user if errors: return form.notifyErrors(errors) self.setItem('Form', form.getFormName()) # process editable fields (we read the submitted value in the request) form.readInputs(self, REQUEST, process_attachments=True) # refresh computed values, run onSave, reindex self.save(form, creation) redirect = REQUEST.get('plominoredirecturl') if not redirect: redirect = self.getItem("plominoredirecturl") if type(redirect) is dict: # if dict, we assume it contains "callback" as an URL that will be # called asynchronously, "redirect" as the redirect url (optional, # default=doc url), and "method" (optional, default=GET) redirect = "./async_callback?" + urlencode(redirect) if not redirect: redirect = self.absolute_url() REQUEST.RESPONSE.redirect(redirect)
class OrderedContainer(Persistent, Contained): """ `OrderedContainer` maintains entries' order as added and moved. >>> oc = OrderedContainer() >>> int(IOrderedContainer.providedBy(oc)) 1 >>> len(oc) 0 """ implements(IOrderedContainer) def __init__(self): self._data = PersistentDict() self._order = PersistentList() def keys(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.keys() ['foo'] >>> oc['baz'] = 'quux' >>> oc.keys() ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 """ return self._order[:] def __iter__(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc['baz'] = 'quux' >>> [i for i in oc] ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 """ return iter(self.keys()) def __getitem__(self, key): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc['foo'] 'bar' """ return self._data[key] def get(self, key, default=None): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc.get('foo') 'bar' >>> oc.get('funky', 'No chance, dude.') 'No chance, dude.' """ return self._data.get(key, default) def values(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.values() ['bar'] >>> oc['baz'] = 'quux' >>> oc.values() ['bar', 'quux'] >>> int(len(oc._order) == len(oc._data)) 1 """ return [self._data[i] for i in self._order] def __len__(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> int(len(oc) == 0) 1 >>> oc['foo'] = 'bar' >>> int(len(oc) == 1) 1 """ return len(self._data) def items(self): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc.items() [('foo', 'bar')] >>> oc['baz'] = 'quux' >>> oc.items() [('foo', 'bar'), ('baz', 'quux')] >>> int(len(oc._order) == len(oc._data)) 1 """ return [(i, self._data[i]) for i in self._order] def __contains__(self, key): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> int('foo' in oc) 1 >>> int('quux' in oc) 0 """ return self._data.has_key(key) has_key = __contains__ def __setitem__(self, key, object): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc._order ['foo'] >>> oc['baz'] = 'quux' >>> oc._order ['foo', 'baz'] >>> int(len(oc._order) == len(oc._data)) 1 """ existed = self._data.has_key(key) bad = False if isinstance(key, StringTypes): try: unicode(key) except UnicodeError: bad = True else: bad = True if bad: raise TypeError("'%s' is invalid, the key must be an " "ascii or unicode string" % key) if len(key) == 0: raise ValueError("The key cannot be an empty string") setitem(self, self._data.__setitem__, key, object) if not existed: self._order.append(key) return key def __delitem__(self, key): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc.keys() [] >>> oc['foo'] = 'bar' >>> oc['baz'] = 'quux' >>> oc['zork'] = 'grue' >>> oc.items() [('foo', 'bar'), ('baz', 'quux'), ('zork', 'grue')] >>> int(len(oc._order) == len(oc._data)) 1 >>> del oc['baz'] >>> oc.items() [('foo', 'bar'), ('zork', 'grue')] >>> int(len(oc._order) == len(oc._data)) 1 """ uncontained(self._data[key], self, key) del self._data[key] self._order.remove(key) def updateOrder(self, order): """ See `IOrderedContainer`. >>> oc = OrderedContainer() >>> oc['foo'] = 'bar' >>> oc['baz'] = 'quux' >>> oc['zork'] = 'grue' >>> oc.keys() ['foo', 'baz', 'zork'] >>> oc.updateOrder(['baz', 'foo', 'zork']) >>> oc.keys() ['baz', 'foo', 'zork'] >>> oc.updateOrder(['baz', 'zork', 'foo']) >>> oc.keys() ['baz', 'zork', 'foo'] >>> oc.updateOrder(['baz', 'zork', 'foo']) >>> oc.keys() ['baz', 'zork', 'foo'] >>> oc.updateOrder(('zork', 'foo', 'baz')) >>> oc.keys() ['zork', 'foo', 'baz'] >>> oc.updateOrder(['baz', 'zork']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> oc.updateOrder(['foo', 'bar', 'baz', 'quux']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> oc.updateOrder(1) Traceback (most recent call last): ... TypeError: order must be a tuple or a list. >>> oc.updateOrder('bar') Traceback (most recent call last): ... TypeError: order must be a tuple or a list. >>> oc.updateOrder(['baz', 'zork', 'quux']) Traceback (most recent call last): ... ValueError: Incompatible key set. >>> del oc['baz'] >>> del oc['zork'] >>> del oc['foo'] >>> len(oc) 0 """ if not isinstance(order, ListType) and \ not isinstance(order, TupleType): raise TypeError('order must be a tuple or a list.') if len(order) != len(self._order): raise ValueError("Incompatible key set.") was_dict = {} will_be_dict = {} new_order = PersistentList() for i in range(len(order)): was_dict[self._order[i]] = 1 will_be_dict[order[i]] = 1 new_order.append(order[i]) if will_be_dict != was_dict: raise ValueError("Incompatible key set.") self._order = new_order notifyContainerModified(self)
class NyLocalizedBFile(NyContentData, NyAttributes, NyItem, NyCheckControl, NyValidation, NyContentType): """ """ implements(INyBFile) meta_type = config['meta_type'] meta_label = config['label'] manage_options = ( {'label': 'Properties', 'action': 'manage_edit_html'}, {'label': 'Edit', 'action': 'manage_main'}, {'label': 'View', 'action': 'index_html'}, ) + NyItem.manage_options security = ClassSecurityInfo() def __init__(self, id, contributor): self.id = id NyContentData.__init__(self) NyValidation.__dict__['__init__'](self) NyCheckControl.__dict__['__init__'](self) NyItem.__dict__['__init__'](self) self.contributor = contributor self._versions = PersistentDict() security.declarePrivate('current_version') @property def current_version(self): language = self.get_selected_language() hasKey = self._versions.has_key(language) if hasKey == True: _versions = self._versions[language] for ver in reversed(_versions): if not ver.removed: return ver else: return None security.declareProtected(view, 'current_version_download_url') def current_version_download_url(self): language = self.get_selected_language() versions = self._versions_for_tmpl(language) if versions: return versions[-1]['url'] else: return None security.declarePrivate('remove_version') def remove_version(self, number, language, removed_by=None): if (not self._versions[language]) or (not self._versions[language][number]): raise ValueError # pick a random error ver = self._versions[language][number] if ver.removed: return ver.removed = True ver.removed_by = removed_by ver.removed_at = datetime.utcnow() ver.size = None f = ver.open_write() f.write('') f.close() def _save_file(self, the_file, language, contributor): """ """ bf = make_blobfile(the_file, removed=False, timestamp=datetime.utcnow(), contributor=contributor) _versions = self._versions.pop(language, None) if _versions == None: toAdd = [bf] newD = {language:toAdd} self._versions.update(newD) else: _versions.append(bf) newD = {language:_versions} self._versions.update(newD) def _versions_for_tmpl(self, language): """ """ hasKey = self._versions.has_key(language) if hasKey == True: _versions = self._versions[language] versions = [tmpl_version(self, ver, str(n+1)) for n, ver in enumerate(_versions) if not ver.removed] if versions: versions[-1]['is_current'] = True return versions else: return None security.declareProtected(view, 'index_html') def index_html(self, REQUEST=None, RESPONSE=None): """ """ language = self.get_selected_language() versions = self._versions_for_tmpl(language) options = {'versions': versions} if versions: options['current_version'] = versions[-1] template_vars = {'here': self, 'options': options} to_return = self.getFormsTool().getContent(template_vars, 'localizedbfile_index') return to_return def isVersionable(self): """ Localized BFiles are not versionable""" return False security.declareProtected(PERMISSION_EDIT_OBJECTS, 'saveProperties') def saveProperties(self, REQUEST=None, **kwargs): """ """ if not self.checkPermissionEditObject(): raise EXCEPTION_NOTAUTHORIZED, EXCEPTION_NOTAUTHORIZED_MSG if REQUEST is not None: schema_raw_data = dict(REQUEST.form) else: schema_raw_data = kwargs _lang = schema_raw_data.pop('_lang', schema_raw_data.pop('lang', None)) _releasedate = self.process_releasedate(schema_raw_data.pop('releasedate', ''), self.releasedate) _uploaded_file = schema_raw_data.pop('uploaded_file', None) versions_to_remove = schema_raw_data.pop('versions_to_remove', []) form_errors = self.process_submitted_form(schema_raw_data, _lang, _override_releasedate=_releasedate) if form_errors: if REQUEST is not None: self._prepare_error_response(REQUEST, form_errors, schema_raw_data) REQUEST.RESPONSE.redirect('%s/edit_html?lang=%s' % (self.absolute_url(), _lang)) return else: raise ValueError(form_errors.popitem()[1]) # pick a random error contributor = self.REQUEST.AUTHENTICATED_USER.getUserName() for ver_id in reversed(versions_to_remove): self.remove_version(int(ver_id) - 1, _lang, contributor) self._p_changed = 1 self.recatalogNyObject(self) #log date auth_tool = self.getAuthenticationTool() auth_tool.changeLastPost(contributor) if file_has_content(_uploaded_file): self._save_file(_uploaded_file, _lang, contributor) notify(NyContentObjectEditEvent(self, contributor)) if REQUEST: self.setSessionInfoTrans(MESSAGE_SAVEDCHANGES, date=self.utGetTodayDate()) REQUEST.RESPONSE.redirect('%s/edit_html?lang=%s' % (self.absolute_url(), _lang)) security.declareProtected(PERMISSION_EDIT_OBJECTS, 'edit_html') def edit_html(self, REQUEST=None, RESPONSE=None): """ """ hasKey = REQUEST.form.has_key('lang') if hasKey == False: language = self.get_selected_language() else: language = REQUEST.form['lang'] options = {'versions': self._versions_for_tmpl(language)} template_vars = {'here': self, 'options': options} to_return = self.getFormsTool().getContent(template_vars, 'localizedbfile_edit') return to_return security.declareProtected(view, 'download') download = CaptureTraverse(localizedbfile_download)
class NyLocalizedBFile(NyContentData, NyAttributes, NyItem, NyCheckControl, NyValidation, NyContentType): """ """ implements(INyBFile) meta_type = config['meta_type'] meta_label = config['label'] manage_options = ( { 'label': 'Properties', 'action': 'manage_edit_html' }, { 'label': 'Edit', 'action': 'manage_main' }, { 'label': 'View', 'action': 'index_html' }, ) + NyItem.manage_options security = ClassSecurityInfo() def __init__(self, id, contributor): self.id = id NyContentData.__init__(self) NyValidation.__dict__['__init__'](self) NyCheckControl.__dict__['__init__'](self) NyItem.__dict__['__init__'](self) self.contributor = contributor self._versions = PersistentDict() security.declarePrivate('current_version') @property def current_version(self): language = self.get_selected_language() hasKey = self._versions.has_key(language) if hasKey == True: _versions = self._versions[language] for ver in reversed(_versions): if not ver.removed: return ver else: return None security.declareProtected(view, 'current_version_download_url') def current_version_download_url(self): language = self.get_selected_language() versions = self._versions_for_tmpl(language) if versions: return versions[-1]['url'] else: return None security.declarePrivate('remove_version') def remove_version(self, number, language, removed_by=None): if (not self._versions[language]) or ( not self._versions[language][number]): raise ValueError # pick a random error ver = self._versions[language][number] if ver.removed: return ver.removed = True ver.removed_by = removed_by ver.removed_at = datetime.utcnow() ver.size = None f = ver.open_write() f.write('') f.close() def _save_file(self, the_file, language, contributor): """ """ bf = make_blobfile(the_file, removed=False, timestamp=datetime.utcnow(), contributor=contributor) _versions = self._versions.pop(language, None) if _versions == None: toAdd = [bf] newD = {language: toAdd} self._versions.update(newD) else: _versions.append(bf) newD = {language: _versions} self._versions.update(newD) def _versions_for_tmpl(self, language): """ """ hasKey = self._versions.has_key(language) if hasKey == True: _versions = self._versions[language] versions = [ tmpl_version(self, ver, str(n + 1)) for n, ver in enumerate(_versions) if not ver.removed ] if versions: versions[-1]['is_current'] = True return versions else: return None security.declareProtected(view, 'index_html') def index_html(self, REQUEST=None, RESPONSE=None): """ """ language = self.get_selected_language() versions = self._versions_for_tmpl(language) options = {'versions': versions} if versions: options['current_version'] = versions[-1] template_vars = {'here': self, 'options': options} to_return = self.getFormsTool().getContent(template_vars, 'localizedbfile_index') return to_return def isVersionable(self): """ Localized BFiles are not versionable""" return False security.declareProtected(PERMISSION_EDIT_OBJECTS, 'saveProperties') def saveProperties(self, REQUEST=None, **kwargs): """ """ if not self.checkPermissionEditObject(): raise EXCEPTION_NOTAUTHORIZED, EXCEPTION_NOTAUTHORIZED_MSG if REQUEST is not None: schema_raw_data = dict(REQUEST.form) else: schema_raw_data = kwargs _lang = schema_raw_data.pop('_lang', schema_raw_data.pop('lang', None)) _releasedate = self.process_releasedate( schema_raw_data.pop('releasedate', ''), self.releasedate) _uploaded_file = schema_raw_data.pop('uploaded_file', None) versions_to_remove = schema_raw_data.pop('versions_to_remove', []) form_errors = self.process_submitted_form( schema_raw_data, _lang, _override_releasedate=_releasedate) if form_errors: if REQUEST is not None: self._prepare_error_response(REQUEST, form_errors, schema_raw_data) REQUEST.RESPONSE.redirect('%s/edit_html?lang=%s' % (self.absolute_url(), _lang)) return else: raise ValueError( form_errors.popitem()[1]) # pick a random error contributor = self.REQUEST.AUTHENTICATED_USER.getUserName() for ver_id in reversed(versions_to_remove): self.remove_version(int(ver_id) - 1, _lang, contributor) self._p_changed = 1 self.recatalogNyObject(self) #log date auth_tool = self.getAuthenticationTool() auth_tool.changeLastPost(contributor) if file_has_content(_uploaded_file): self._save_file(_uploaded_file, _lang, contributor) notify(NyContentObjectEditEvent(self, contributor)) if REQUEST: self.setSessionInfoTrans(MESSAGE_SAVEDCHANGES, date=self.utGetTodayDate()) REQUEST.RESPONSE.redirect('%s/edit_html?lang=%s' % (self.absolute_url(), _lang)) security.declareProtected(PERMISSION_EDIT_OBJECTS, 'edit_html') def edit_html(self, REQUEST=None, RESPONSE=None): """ """ hasKey = REQUEST.form.has_key('lang') if hasKey == False: language = self.get_selected_language() else: language = REQUEST.form['lang'] options = {'versions': self._versions_for_tmpl(language)} template_vars = {'here': self, 'options': options} to_return = self.getFormsTool().getContent(template_vars, 'localizedbfile_edit') return to_return security.declareProtected(view, 'download') download = CaptureTraverse(localizedbfile_download)