Ejemplo n.º 1
0
class StructuredMilestone(object):
    """The model for structured milestone."""
    __proxy_attrs__ = ['name', 'due', 'completed', 'description', 'resource', 'exists', 'is_completed', 'is_late']
    _kids = None
    _level = None
    def __init__(self, env, milestone=None, db=None):
        self.env = env
        if not isinstance(milestone, Milestone):
            milestone = Milestone(env, milestone)
            
        self.milestone = milestone
        self.ticket = Ticket(self.env)
        self.ticket.fields = MilestoneSystem(self.env).get_milestone_fields()
        self.ticket.values = {}
        self.ticket['summary'] = milestone.name        
        self.ticket['type'] = milestone_ticket_type
        self.ticket._old={}
        
        if self.exists:
            self._fetch(milestone.name, db)
    
    def __getattribute__(self, name):
        if name in object.__getattribute__(self, "__proxy_attrs__"):
            return getattr(object.__getattribute__(self, "milestone"), name)
        return object.__getattribute__(self, name)
    
    def __setattr__(self, name, value):
        if name in object.__getattribute__(self, "__proxy_attrs__"):
            setattr(object.__getattribute__(self, "milestone"), name, value)
        else:
            self.__dict__[name]=value
    
    parent = property(fget= lambda self: self.ticket.values.get('milestone'))
    is_started = property(fget=lambda self: self.ticket.values.get('started') is not None)
    level = property(fget = lambda self: self._get_level(), fset = lambda self, val: self._set_level(val))
    can_be_closed = property(lambda self: self._can_be_closed())
    kids = property (lambda self: self._get_kids())
    
    def _fetch(self, name, db=None):
        if not db:
            db = self.env.get_db_cnx()
            
        cursor = db.cursor()
        cursor.execute("SELECT id"
                        " FROM ticket"
                       " WHERE summary=%s"
                         " AND type=%s", (name, milestone_ticket_type))
        row = cursor.fetchone()
        if not row:
            raise ResourceNotFound('Associated Ticket %s does not exist.' % name,
                                   'Invalid Milestone State')
        self.ticket._fetch_ticket(row[0], db)

    def _get_kids(self):
        if self._kids is None:
            db = self.env.get_db_cnx()
            cursor = db.cursor()
            cursor.execute("SELECT m.name "
                            " FROM milestone m,"
                                 " ticket t"
                           " WHERE m.name=t.summary"
                             " AND t.milestone=%s"
                             " AND t.type=%s", (self.name, milestone_ticket_type))
            self._kids = [StructuredMilestone(self.env, name) for name, in cursor]
        return self._kids

    
    def _can_be_closed(self):
        kids = self.kids
        if kids:
            for kid in kids:
                if not kid.is_completed:
                    return False
        return True

    def _get_level(self):
        if self._level:
            return self._level
        lev = 0
        if self.parent:
            parent_milestone = StructuredMilestone(self.env, self.parent)
            if parent_milestone.exists:
                lev = parent_milestone.level['index'] +1
        self._level = {'index':lev, 'label': self._get_level_label(lev)}
        return self._level
    
    def _set_level(self, lev):
        int_lev = int(lev)
        self._level = {'index':int_lev, 'label': self._get_level_label(int_lev)}
        
    def _get_level_label(self, idx):
        label = 'undefined'
        levels = IttecoEvnSetup(self.env).milestone_levels
        if levels and idx < len(levels):
            label = levels[idx]
        return label

    def delete(self, retarget_to=None, author=None, db=None):
        handle_commit = False
        if not db:
            db = self.env.get_db_cnx()
            handle_commit = True

        self.milestone.delete(retarget_to, author, db)
        self.ticket.delete(db)
        if handle_commit:
            db.commit()
            
        listeners = IttecoEvnSetup(self.env).change_listeners
        for listener in listeners:
            listener.milestone_deleted(self)


    def insert(self, db=None):
        assert self.name, 'Cannot create milestone with no name'
        handle_commit = False
        if not db:
            db = self.env.get_db_cnx()
            handle_commit = True

        self.milestone.insert(db)
        self.ticket.insert(db=db)
        if handle_commit:
            db.commit()
            
        listeners = IttecoEvnSetup(self.env).change_listeners
        for listener in listeners:
            listener.milestone_created(self)

    def save_changes(self, author, comment, when=None, db=None, cnum=''):
        assert self.name, 'Cannot update milestone with no name'
        handle_commit = False
        if not db:
            db = self.env.get_db_cnx()
            handle_commit = True
        old_values =  self.ticket._old
                
        self.milestone.update(db)
        self.ticket.save_changes(author, comment, when, db, cnum)
        
        if handle_commit:
            db.commit()
            
        old_values['name'] = self.name
        listeners = IttecoEvnSetup(self.env).change_listeners
        for listener in listeners:
            listener.milestone_changed(self, old_values)
    
    @staticmethod
    def select(env, include_completed=True, db=None):
        if not db:
            db = env.get_db_cnx()
            
        milestones = [ StructuredMilestone(env, milestone) \
                        for milestone in Milestone.select(env, include_completed, db)]
        return StructuredMilestone.reorganize(milestones)
           
    @staticmethod
    def reorganize(milestones):
        if not milestones:
            return milestones
        for milestone in milestones:
            milestone._kids = []

        grouped = partition((milestone, milestone.parent) for milestone in milestones)
        roots = []
        name_to_struct = {}
        delayed_items ={}
        for parent, kids in grouped.iteritems():
            target = roots
            if parent:
                if name_to_struct.has_key(parent):
                    target =  name_to_struct[parent].kids
                else:
                    target = delayed_items.setdefault(parent, [])
            for child in kids:
                child.kids.extend(delayed_items.pop(child.name,[]))
                name_to_struct[child.name] = child
                target.append(child)
        return StructuredMilestone._deep_sort(roots)
    
    @staticmethod
    def _deep_sort(mils):
        def milestone_order(m):
            return (m.completed or utcmax,
                    m.due or utcmax,
                    embedded_numbers(m.name))
        mils.sort(key=milestone_order)
        for m in mils:
            StructuredMilestone._deep_sort(m.kids)
        return mils

    def __str__(self):
        return "StructuredMilestone<name='%s', kids='%s'>" % (self.name, self.kids)
        
    __repr__=__str__