コード例 #1
0
ファイル: DocumentBank.py プロジェクト: ksiktforum/ksiktforum
class DocumentBank(Topic):
    """ A documentbank is a topic where you are able to arrange attachments in an hierarchical way. """
    isObjectManager = True
    isPrincipiaFolderish = True

    meta_type = 'Topic'
    
    security = ClassSecurityInfo()
    security.declareObjectProtected(View)       
    
    
    def __init__(self, topicid, *args, **kw):
        self.agendaManager = IOBTree()
        self.agendaTopLevel = []
        Topic.__init__(self, topicid, *args, **kw)
    
    
    def manage_afterAdd(self, container, item):
        Topic.manage_afterAdd(self, container, item)        
        
        
    def documentbanktopic(self):
        """ The documentbank itself. """
        return self.aq_inner
        
    security.declarePrivate('notifyWorkflowCreated')
    def notifyWorkflowCreated(self):
        """
            Notify the workflow that self was just created.
        """       
        wftool = self._getWorkflowTool()
        if wftool is not None:
            wftool.notifyCreated(self)
        #self._View_Permission = ['Editor', 'Manager']#list(self._View_Permission)

    def addAgendaObject(self, title, ingress, invokedOn=0, level=0):        
        invokedOnAgendaNode =  self.agendaManager.get(invokedOn, None)       
        agendaNode = None    
        if invokedOnAgendaNode:                    
            if level == 0:
                #same level
                agendaNode = AgendaObject(title, ingress, parent=invokedOnAgendaNode.parent)
                children = self.agendaTopLevel
                if invokedOnAgendaNode.parent:
                    parent = self.agendaManager.get(invokedOnAgendaNode.parent, None)
                    parent.p_modified = True
                    children = parent.children
                else:
                    self.p_modified = True
                    
                index = 0                
                
                for serial in children:
                    if serial == invokedOn:
                        children.insert(index+1, agendaNode.serial)
                        break;
                    index = index + 1
                
            elif level == 1:
                #level below                
                parent = invokedOnAgendaNode.serial                                                                
                agendaNode = AgendaObject(title, ingress, parent=parent)
                invokedOnAgendaNode.children.append(agendaNode.serial)
                invokedOnAgendaNode._p_changed = True                
        #bootstrap
        else:
            agendaNode = AgendaObject(title, ingress, parent=0)
            self.agendaTopLevel.append(agendaNode.serial)
        
        if agendaNode:
            self.agendaManager.insert(agendaNode.serial, agendaNode)            
        self._p_changed = True        
        
    def removeAgendaObject(self, invokedOn):
        invokedOnNode = self.agendaManager.get(invokedOn, None)
        if invokedOnNode:
            parentNode = self.agendaManager.get(invokedOnNode.parent, None)
            siblings = self.agendaTopLevel
            if parentNode:
                siblings = parentNode.children
                parentNode._p_changed = True
            else:
                self._p_changed = True
                
            children = invokedOnNode.children
            
            
            def recursiveRemove(children):          
                for child in children:
                    try:
                        recursiveRemove(self.agendaManager.get(child, None).children)
                    except AttributeError:
                        pass                        
                    del(self.agendaManager[child])                    
            #Remove all children from the node we want to remove as well.
            recursiveRemove(children)
            
                    
            siblings.remove(invokedOn)
            del(self.agendaManager[invokedOn])
            
                
        
    def indentAgendaObject(self, invokedOn):
        invokedOnNode = self.agendaManager.get(invokedOn, None)
        if invokedOnNode:
            parentNode = self.agendaManager.get(invokedOnNode.parent, None)
            children = self.agendaTopLevel
            if parentNode:
                children = parentNode.children
                parentNode._p_changed = True
            else:
                self._p_changed = True
            index = 0
            for serial in children:
                if serial == invokedOnNode.serial:                    
                    if index == 0:
                        raise AssertionError, "can't indent"
                    #get previous node
                    prevSibling = self.agendaManager.get(children[index-1], None)                    
                    #make previous node parent
                    invokedOnNode.parent = prevSibling.serial
                    #add node to new parent children
                    prevSibling.children.append(invokedOn)
                    prevSibling._p_changed = True
                    #remove node from current parent                    
                    children.remove(invokedOnNode.serial)
                    break
                index = index+1            
        
        
        return True
        
                        
        
    def outdentAgendaObject(self, invokedOn):
        invokedOnNode = self.agendaManager.get(invokedOn, None)
        if invokedOnNode:
            parentNode = self.agendaManager.get(invokedOnNode.parent, None)            
            if not parentNode:                
                raise SyntaxError, "can't outdent"            
            parentNode.children.remove(invokedOn)
            parentNode._p_changed = True
            grandparentNode = self.agendaManager.get(parentNode.parent, None)
            children = self.agendaTopLevel
            if grandparentNode:
                children = grandparentNode.children
                grandparentNode._p_changed = True
            else:
                self._p_changed = True
            
            index = 0
            for serial in children:
                if serial == parentNode.serial:
                    children.insert(index+1, invokedOn)
                    break
                index = index+1                
            #set new parent
            invokedOnNode.parent = parentNode.parent
        
        return True
        
    
    def moveAgendaObjectUp(self, invokedOn):
        invokedOnNode = self.agendaManager.get(invokedOn, None)
        if invokedOnNode:
            parentNode = self.agendaManager.get(invokedOnNode.parent, None)
            children = self.agendaTopLevel
            if parentNode:
                children = parentNode.children
                parentNode._p_changed = True
            else:
                self._p_changed = True
            index = 0
            for serial in children:
                if serial == invokedOnNode.serial:                    
                    if index == 0:
                        raise AssertionError, "on the top"
                    else:
                        children.remove(invokedOnNode.serial)
                        children.insert(index-1, invokedOnNode.serial)
                    break
                index = index+1            
        
        
        return True
        
        
    def moveAgendaObjectDown(self, invokedOn):
        invokedOnNode = self.agendaManager.get(invokedOn, None)
        if invokedOnNode:
            parentNode = self.agendaManager.get(invokedOnNode.parent, None)
            children = self.agendaTopLevel
            if parentNode:
                children = parentNode.children
                parentNode._p_changed = True
            else:
                self._p_changed = True
            index = 0
            for serial in children:
                if serial == invokedOnNode.serial:                    
                    if index == len(children)-1:
                        raise AssertionError, "on the bottom"
                    else:
                        children.remove(invokedOnNode.serial)
                        children.insert(index+1, invokedOnNode.serial)
                    break
                index = index+1
        
        
        return True
                
        
    security.declareProtected(View, 'getAgendaNode')
    def getAgendaNode(self, serial):        
        return self.agendaManager.get(serial, None)
    
    def getAgenda(self):    
        return self.agendaTopLevel

    security.declareProtected(ModifyPortalContent, 'uploadFile')
    def uploadFile(self, fileObject, title, overwrite=False):
        topicmap = self.portal_topicmaps.getTopicMap()
        atbsi = topicmap.assertTopicBySubjectIdentifier              
        filetopictype = atbsi(psis.file)

        #TODO: get path
        creationpath = getattr(self, 'filearchive')

        filename = altTopicTitle = self.portal_topicmanagement.extractFilename(unicode(fileObject.filename, 'utf8'))
        
        origname = filename = self.portal_topicmanagement.normalizeid(filename)

        counter = 1

        
        idIsAvailable = creationpath.checkIdAvailable(filename)
        topicid = filename+".topic"
        if not idIsAvailable:
            if overwrite and getattr(creationpath, topicid, False):
                #delete file.      
                creationpath.manage_delObjects([filename])                
                filetopic = getattr(creationpath, topicid)
                #update title if set
                if title:                    
                    filetopic.setTitleAndName(title)
                idIsAvailable = True
            else:
                raise AssertionError, "%s already exists. If you want to overwrite this file you must check the checkbox titled 'Overwrite existing file'"%title
            
        checkIdAvailable = creationpath.checkIdAvailable
        while not idIsAvailable:
            filename = origname[0:origname.rindex('.')]+'_'+str(counter)+'_'+origname[origname.rindex('.'):]
            counter += 1        
            idIsAvailable = checkIdAvailable(filename)    
            if counter >= 50:
                raise AssertionError, "You entered an endless loop during fileupload. This should not have happened. Please write down the steps you used to trigger this bug and report it to the ZTM developers."

        if not title:
            title = altTopicTitle            
        
        self.REQUEST.set('type_name', 'File')
        creationpath.invokeFactory(type_name='File', id=filename)
        newfile = getattr(creationpath, filename)
        newfile.manage_upload(fileObject)
            
        
        #create file topic. set file as subjectlocatior    
        if not getattr(creationpath, topicid, False):                    
            self.REQUEST.set('type_name', 'file')
            creationpath.invokeFactory(type_name='file', id=topicid)
            filetopic = getattr(creationpath, topicid)    
            filetopic.setTitleAndName(title)
            filetopic.addSubjectLocator('x-zope-path:' + '/'.join(newfile.getPhysicalPath()))            
        else:
            if overwrite:
                #overwrite file clear subject locators:            
                filetopic = getattr(creationpath, topicid)
                for locator in filetopic.getSubjectLocators():
                    filetopic.removeSubjectLocator(locator)
                #set new subject locator
                filetopic.addSubjectLocator('x-zope-path:' + '/'.join(newfile.getPhysicalPath()))            
            
        filetopic.reindexObject()  
        return filetopic.tm_serial
       
    security.declareProtected(ModifyPortalContent, 'openForAnonymousUsers')
    def openForAnonymousUsers(self, topic=None):
          #topic not given, open up the documentbank itself
        if not topic:
            topic = self
        allowedToAccessContent = list(getattr(topic, '_Access_contents_information_Permission', []))    
        if 'Anonymous' not in allowedToAccessContent:
            allowedToAccessContent.append('Anonymous')        
        topic.manage_permission("Access contents information", allowedToAccessContent, acquire=0)
        
        allowedToViewContent = list(getattr(topic, '_View_Permission', []))    
        if 'Anonymous' not in allowedToViewContent:
            allowedToViewContent.append('Anonymous')        
        topic.manage_permission("View", allowedToViewContent, acquire=0)        
        
    security.declareProtected(ModifyPortalContent, 'closeForAnonymousUsers')
    def closeForAnonymousUsers(self, topic=None):
        #topic not given, close down the documentbank itself
        if not topic:
            lazy = self.portal_catalog(path='/'.join(self.getPhysicalPath()), types=[psis.file], sort_on='modified', sort_order='Reverse')
            for brain in lazy:
                topic = brain.getObject()
                self.closeForAnonymousUsers(topic)            
            topic = self
            
        allowedToAccessContent = list(getattr(topic, '_Access_contents_information_Permission', []))        
        for user in allowedToAccessContent:
            if user == 'Anonymous':
                allowedToAccessContent.remove(user)
        topic.manage_permission("Access contents information",allowedToAccessContent, acquire=0)
        
        allowedToViewContent = list(getattr(topic, '_View_Permission', []))    
        for user in allowedToViewContent:
            if user == 'Anonymous':
                allowedToViewContent.remove(user)   
        topic.manage_permission("View", allowedToViewContent, acquire=0)   
           
    security.declareProtected(View, 'isOpen')
    def isOpen(self):
        allowedToAccessContent = list(getattr(self, '_Access_contents_information_Permission', []))       
        allowedToViewContent = list(getattr(self, '_View_Permission', []))
        
        if 'Anonymous' in allowedToAccessContent and 'Anonymous' in allowedToViewContent:
            return True
        else:
            return False
    
    security.declareProtected(View, 'fileArchiveContents')
    def fileArchiveContents(self):
        return {} #mark
        files = []
        append = files.append
        lazy = self.portal_catalog(path='/'.join(self.filearchive.getPhysicalPath()), types=[psis.file], sort_on='modified', sort_order='Reverse')
        for brain in lazy:
            topic = brain.getObject()    
            fileobject = topic.resource_object()
            content_type = fileobject and fileobject.content_type or ""           
            filetype = filetypes.has_key(content_type) and filetypes[content_type] or "fil"                
            file_icon = fileicons[filetype]
            file_type = filenames[filetype]    
    
            allowedToAccessContent = list(getattr(topic, '_Access_contents_information_Permission', []))       
            allowedToViewContent = list(getattr(topic, '_View_Permission', []))
            is_open = bool('Anonymous' in allowedToAccessContent and 'Anonymous' in allowedToViewContent)
    
    
            append({'title':topic.title_or_id()
            ,'filetitle':fileobject.title_or_id()
            ,'Creator':topic.Creator
            ,'iconclass':file_icon
            ,'modified': DateTime(topic.modified()).strftime('%d.%m.%Y %H:%M')
            ,'tm_serial':topic.tm_serial
            ,'url':fileobject.absolute_url()
            ,'is_open':is_open
                
            })
            
        files = [(x['title_or_id'],x) for x in files]
	files.sort()
	files = [y for (x,y) in files]

        return files     
        
    security.declareProtected(ModifyPortalContent, 'publishFiles')
    def publishFiles(self, tm_serials):
        topicmap = self.getTopicMap()
        gtbs = topicmap.getTopicBySerial
        for tm_serial in tm_serials:
            
            try:            
                topic = gtbs(tm_serial)
                self.openForAnonymousUsers(topic) 
                topic.reindexObject()
            except KeyError:
                pass
                
    security.declareProtected(ModifyPortalContent, 'retractFiles')
    def retractFiles(self, tm_serials):
        topicmap = self.getTopicMap()
        gtbs = topicmap.getTopicBySerial
        for tm_serial in tm_serials:
            try:
                topic = gtbs(tm_serial)
                self.closeForAnonymousUsers(topic)
                topic.unindexObject()
                topic.indexObject()
            except KeyError:
                pass
コード例 #2
0
ファイル: book.py プロジェクト: paritworkercoop/bokeep-mirror
class BoKeepBook(Persistent):
    """The equivilent of an accounting book in BoKeep.

    Meaning there should be one of these per entity keeping accounting
    records of itself.

    Each BoKeep book has frontend plugins (as specified by
    bokeep.prototype_plugin.ProtoTypePlugin) that provide transaction types.
    The eventual intent is that there can be multiple
    frontend plugin INSTANCES per frontend plugin in each book, that way
    the same frontend plugin can be used multiple times in a book but with
    a different configuration. Some steps in this direction have been taken,
    the plugin class from each plugin is instantiated, that is class variables
    aren't relied on, etc. Biggest barrier to this right now is that the
    plugin module/package name is used to identify each instance

    Its already the case the separate BoKeepBook's in the same BoKeepBookSet
    can each use the same frontend plugin, but with a different configuration
    each.

    Each book contains BoKeep transactions (bokeep.book_transaction.Trasaction)
    of those transaction types from the frontend plugins. These are
    indexed by assigned transaction ids in a BTree. (which allows for
    both fast map style direct lookup and linear, linked list style iteration)

    A book also has a backend plugin so that its transactions can be
    mirrored in a "real" accounting program. The backend plugin
    should be informed when a BoKeep transaction
    (bokeep.book_transaction.Transaction) is out of sync, as per the
    bokeep.backend_plugins.BackendPlugin api.

    Note that the fact that multiple front end plugins are allowed but only one
    backend plugin per book isn't an oversight -- the former is essential, the
    later has no obvious use case. I'd suggest that if someone does want
    multiple backend plugins per BoKeepBook that they design a Multiplex
    backend plugin to hide this and allow the simplicity of only dealing
    with one backend plugin to stay.
    """
    
    def __init__(self, new_book_name):
        self.book_name = new_book_name
        self.trans_tree = IOBTree()
        self.set_backend_plugin(DEFAULT_BACKEND_MODULE)
        self.enabled_modules = {}
        self.disabled_modules = {}

    def add_frontend_plugin(self, plugin_name):
        """Add a frontend plugin to this BoKeep book, starting in a disabled
        state.  FrontendPluginImportError is thrown if there's a problem."""
        
        assert( plugin_name not in self.enabled_modules and 
                plugin_name not in self.disabled_modules )
        # get the module class and instantiate as a new disabled module
        try:
            self.disabled_modules[plugin_name] =  __import__(
                plugin_name, globals(), locals(), [""]).get_plugin_class()()
            self._p_changed = True
        except ImportError:
            raise FrontendPluginImportError(plugin_name)

    def enable_frontend_plugin(self, plugin_name):
        """Enable a previously added frontend plugin that is currently
        disabled."""
        assert( plugin_name in self.disabled_modules )
        self.enabled_modules[plugin_name] = self.disabled_modules[plugin_name]
        del self.disabled_modules[plugin_name]
        self._p_changed = True
        
    def disable_frontend_plugin(self, plugin_name):
        """Disables a presently enabled frontend plugin."""
        assert( plugin_name in self.enabled_modules )
        self.disabled_modules[plugin_name] = self.enabled_modules[plugin_name]
        del self.enabled_modules[plugin_name]
        self._p_changed = True
    
    def get_frontend_plugin(self, plugin_name):
        return self.enabled_modules[plugin_name]

    def get_frontend_plugins(self):
        return self.enabled_modules

    def has_enabled_frontend_plugin(self, plugin_name):
        return plugin_name in self.enabled_modules

    def has_disabled_frontend_plugin(self, plugin_name):
        return plugin_name in self.disabled_modules

    def has_frontend_plugin(self, plugin_name):
        return self.has_enabled_frontend_plugin(plugin_name) or \
               self.has_disabled_frontend_plugin(plugin_name)

    def get_iter_of_code_class_module_tripplets(self):
        # there has got to be a more functional way to write this..
        # while also maintaining that good ol iterator don't waste memory
        # property... some kind of nice nested generator expressions
        # with some kind of functional/itertool y thing
        for frontend_plugin in self.enabled_modules.itervalues():
            for code in frontend_plugin.get_transaction_type_codes():
                yield (code,
                       frontend_plugin.get_transaction_type_from_code(code),
                       frontend_plugin)

    def get_index_and_code_class_module_tripplet_for_transaction(
        self, trans_id):
        actual_trans = self.get_transaction(trans_id)
        for i, (code, cls, module) in \
                enumerate(self.get_iter_of_code_class_module_tripplets()):
            # the assumption here is that each class only co-responds
            # to one code, that needs to be clarified in the module
            # api
            if module.has_transaction(trans_id) and \
                    actual_trans.__class__ == cls:
                return i, (code, cls, module)
        return None, (None, None, None)

    def set_backend_plugin(self, backend_plugin_name):
        if hasattr(self, '_BoKeepBook__backend_module_name'):
            old_backend_module_name = self.get_backend_plugin_name()
            old_backend_module = self.get_backend_plugin()
        try:
            self.__backend_module_name = backend_plugin_name
            self.__backend_module = __import__(
              backend_plugin_name, globals(), locals(), [""] ).\
    	      get_plugin_class()()
            assert( isinstance(self.__backend_module, BackendPlugin) )
            # because we have changed the backend module, all transactions
            # are now dirty and must be re-written to the new backend module
            for trans_ident, trans in self.trans_tree.iteritems():
                self.__backend_module.mark_transaction_dirty(
                    trans_ident, trans)
            self.__backend_module.flush_backend()
        except ImportError:
            # this is in big trouble if old_backend_module_name isn't set
            # but that should only happen on book instantiation
            self.__backend_module_name = old_backend_module_name
            self.__backend_module = old_backend_module  
            raise BackendPluginImportError(backend_plugin_name)

    def get_backend_plugin(self):
        return self.__backend_module

    def get_backend_plugin_name(self):
        return self.__backend_module_name

    backend_plugin = property(get_backend_plugin, set_backend_plugin)

    def insert_transaction(self, trans):
        """Adds a transaction to this BoKeep book."""
        
        if len(self.trans_tree) == 0:
            largest_in_current = -1
        else:
            largest_in_current = self.trans_tree.maxKey()

        if not hasattr(self, 'largest_key_ever'):
            self.largest_key_ever = largest_in_current

        key = max(largest_in_current, self.largest_key_ever) + 1
        self.largest_key_ever = key
        result = self.trans_tree.insert(key, trans)
        assert( result == 1 )
        return key

    def get_transaction_count(self):
        return len(self.trans_tree)

    def has_transaction(self, trans_id):
        return self.trans_tree.has_key(trans_id)

    def get_previous_trans(self, trans_id):
        if not self.has_transaction(trans_id):
            return None
        try:
            prev_key = self.trans_tree.maxKey(trans_id-1)
        except ValueError:
            return None
        else:
            return prev_key
        
    def has_next_trans(self, trans_id):
        return trans_id < self.trans_tree.maxKey()

    def has_previous_trans(self, trans_id):
        return trans_id > self.trans_tree.minKey()

    def get_next_trans(self, trans_id):
        """Returns the key of the next transaction or None."""
        
        if not self.has_transaction(trans_id):
            return None
        try:
            next_key = self.trans_tree.minKey(trans_id+1)
        except ValueError:
            return None
        else:
            return next_key

    def get_transaction(self, trans_id):
        return self.trans_tree[trans_id]

    def get_latest_transaction_id(self):
        if len(self.trans_tree) == 0:
            return None
        else:
            return self.trans_tree.maxKey()

    def remove_transaction(self, trans_id):
        del self.trans_tree[trans_id]
        self.backend_plugin.mark_transaction_for_removal(trans_id)