Пример #1
0
 def _get_name_action(self, req):
     """Return the name and action parameters from the req"""
     name = req.args.get('name')
     action = req.args.get('action')
     log.debug(self, "Processing request: action:%s name:%s" % \
           (action, name))
     return name, action
Пример #2
0
def create_types(env, type_names, db=None):
    db, handle_ta = get_db_for_write(env, db)
    # Query definitions
    sql_select_type = "SELECT count(*) FROM enum WHERE type = 'ticket_type' AND name = '%s'"
    sql_select_max_value = "SELECT max(value) FROM enum WHERE type = 'ticket_type'"
    sql_insert_type = "INSERT INTO enum (type,name,value) VALUES('ticket_type','%s',%d)"

    # For every default type check, if already in db, otherwise insert it.
    # To consistently insert, we need to know the value of the highest ticket_type entry first.
    cursor = db.cursor()
    cursor.execute(sql_select_max_value)
    ticket_type_max_value = int(cursor.fetchone()[0])
    for t in type_names:
        try:
            cursor.execute(sql_select_type % t)
            if cursor.fetchone()[0] == 0:
                ticket_type_max_value += 1
                debug(env, "ticket_type '%s' not found within table 'enum' - will " \
                      "insert it with value %d..." % (t,ticket_type_max_value))
                # If the type is not present already insert with the next value available
                cursor.execute(sql_insert_type % (t,ticket_type_max_value))
                if handle_ta:
                    db.commit()
            else:
                debug(env, "Found ticket_type '%s' within table 'enum'" % (t))
        except Exception, e:
            if handle_ta:
                db.rollback()
            exception_to_unicode(e)
Пример #3
0
def create_table(env, table, conn=None):
    """
    Creates a the given table in the given environment. The Table
    has to be of type trac.db.Table, and the Environment a 
    trac.env.Environment.
    """
    assert isinstance(env, Environment), \
        "[DB]: env should be an instance of trac.env.Environment, got %s" % type(env)
    assert isinstance(table, Table), \
        "[DB]: table should be an instance of trac.sb.Table, got %s" % type(table)
    # Get The Databse Manager
    dbm = DatabaseManager(env)
    # Get the Connector Object for the current DB schema
    connector, args = dbm._get_connector()
    # Ask the connector to generate the proper DDL for the table
    ddl_gen = connector.to_sql(table)
    # Get a DB Connection from the pool, create a cursor and the table
    conn, handle_ta = get_db_for_write(env, conn)
    try:
        cursor = conn.cursor()
        for statement in ddl_gen:
            debug(env, "[DB]: Table: %s\n%s" % (table.name, statement))
            cursor.execute(statement)
        if handle_ta:
            conn.commit()
        debug(env, "[DB]: Successfully Created Table %s" % table.name)
    except Exception, e:
        if handle_ta:
            conn.rollback()
        error(env, "[DB]: Unable to Create Table %s, an error occurred: %s" % \
                    (table.name, exception_to_unicode(e)))
        raise
Пример #4
0
    def expand_macro(self, formatter, name, content):
        req = formatter.req
        # Analyze the arguments list, that should be in content
        args = content.split(',')
        if len(args) == 0:
            raise TracError("No argument provided for %s." %
                            self.__class__.__name__)

        # The first must be the type of the chart
        chart_type = self._get_chart_type(args[0])
        # The second the Sprint
        sprint_name = self._get_sprint(args[1])
        width, height = self._get_dimensions(args[2:])
        filter_by = None
        if len(args) >= 4:
            filter_by = args[3]

        chart_params = dict(sprint_name=sprint_name,
                            width=width,
                            height=height,
                            filter_by=filter_by)
        debug(self.env, "Params: %s" % chart_params)
        chart = ChartGenerator(self.env).get_chartwidget(
            chart_type, **chart_params)
        chart.prepare_rendering(req)
        return html.DIV(chart.display())
Пример #5
0
    def _fetch_tickets(self, db=None):
        """
        Fetch from the DB the ids, type, status of the tickets planned for this sprint,
        and returns a list of id, type, status.
        """
        params = {"table": BACKLOG_TICKET_TABLE, "scope": self.name}
        t_sql = (
            "SELECT DISTINCT id, type, status FROM ticket INNER JOIN ticket_custom ON "
            "ticket.id=ticket_custom.ticket LEFT OUTER JOIN %(table)s ON "
            "ticket.id=%(table)s.ticket_id WHERE (%(table)s.name='Sprint Backlog' "
            "AND scope='%(scope)s') or (ticket_custom.name='sprint' AND "
            "ticket_custom.value='%(scope)s')" % params
        )

        tickets = [(0, "", "")]

        db, handle_ta = get_db_for_write(self.env, db)
        try:
            cursor = db.cursor()
            debug(self, "SQL (_fetch_tickets_stats): %s" % t_sql)
            cursor.execute(t_sql)
            tickets = cursor.fetchall()
        except:
            if handle_ta:
                db.rollback()
        return tickets
Пример #6
0
def parse_calculated_field(configstring, component=None):
    result = None
    if configstring != None and configstring.strip() != "":
        match = CALCULATE.match(configstring)
        if match:
            field_name = match.group('name')
            operator_name = match.group('operator')
            values = match.group('values')
            conditions = match.group('conditions')
            if operator_name in operators:
                operator = operators[operator_name]
                try:
                    result = (field_name,
                              operator(values, condition_string=conditions))
                    if component:
                        base_msg = u"Setting calculated property: %s => %s:%s|%s"
                        msg = base_msg % (field_name, operator_name, values,
                                          conditions)
                        debug(component, msg)
                except AgiloConfigSyntaxError, e:
                    if component:
                        msg = u"Error while parsing calculated property '%s': %s"
                        error(component, msg % (field_name, unicode(e)))
            else:
                if component:
                    error(component, u"Unkown operator name '%s'" % field_name)
Пример #7
0
 def _rename(self, name, new_name, db=None):
     """Renames this sprint and reassigns all tickets to the new 
     name."""
     # avoid circular imports
     from agilo.scrum.metrics.model import TeamMetrics
     params = {
         'name' : name,
         'new_name' : new_name,
     }
     team_metrics_entry_table = TeamMetrics.TeamMetricsEntry._table.name
     queries = [
         "UPDATE ticket_custom SET value=%(new_name)s WHERE name='sprint' AND value=%(name)s",
         "UPDATE " + team_metrics_entry_table + " SET sprint=%(new_name)s WHERE sprint=%(name)s",
     ]
     db, handle_ta = get_db_for_write(self.env, db)
     try:
         cursor = db.cursor()
         for q in queries:
             debug(self, "RENAME => Executing query: %s (%s)" % (q, params))
             safe_execute(cursor, q, params)
         if handle_ta:
             db.commit()
     except Exception, e:
         if handle_ta:
             db.rollback()
         raise TracError("An error occurred while renaming sprint: %s" % to_unicode(e))
Пример #8
0
 def _save(self, timestamp, value, update=False, db=None):
     """Saves a remaining time value to the database. The update parameter
     decides if the value should be updated (True) or inserted (False)"""
     params = {
         Key.TABLE : BURNDOWN_TABLE,
         Key.TASK_ID : self.task.id,
         Key.DATE : timestamp,
         Key.REMAINING_TIME : value,
     }
     if update:
         sql_query = "UPDATE %(table)s SET remaining_time=%(remaining_time)d " \
                     "WHERE task_id=%(task_id)d AND date=%(date)f" % params
     else:
         sql_query = "INSERT INTO %(table)s (task_id, date, remaining_time) " \
                     "VALUES (%(task_id)s, %(date)s, %(remaining_time)s)" % params
     
     db, handle_ta = get_db_for_write(self.env, db)
     try:
         cursor = db.cursor()
         cursor.execute(sql_query)
         if handle_ta:
             db.commit()
             debug(self, 
                   "DB Committed, saved remaining time (%s) for task %d" % \
                   (params[Key.REMAINING_TIME], self.task.id))
     except Exception, e:
         error(self, to_unicode(e))
         if handle_ta:
             db.rollback()
         raise TracError("Error while saving remaining time: %s" % \
                         to_unicode(e))
Пример #9
0
 def _add_linking_source_to_template_data(self, req, data):
     if 'src' in req.args:
         debug(self, "Got SRC: %s" % req.args['src'])
         try:
             data['src'] = int(req.args['src'])
         except (ValueError, TypeError):
             raise TracError("src (%s) must be a valid ticket id!" % req.args['src'])
Пример #10
0
 def _get_name_action(self, req):
     """Return the name and action parameters from the req"""
     name = req.args.get('name')
     action = req.args.get('action')
     log.debug(self, "Processing request: action:%s name:%s" % \
           (action, name))
     return name, action
Пример #11
0
def create_types(env, type_names, db=None):
    db, handle_ta = get_db_for_write(env, db)
    # Query definitions
    sql_select_type = "SELECT count(*) FROM enum WHERE type = 'ticket_type' AND name = '%s'"
    sql_select_max_value = "SELECT max(value) FROM enum WHERE type = 'ticket_type'"
    sql_insert_type = "INSERT INTO enum (type,name,value) VALUES('ticket_type','%s',%d)"

    # For every default type check, if already in db, otherwise insert it.
    # To consistently insert, we need to know the value of the highest ticket_type entry first.
    cursor = db.cursor()
    cursor.execute(sql_select_max_value)
    ticket_type_max_value = int(cursor.fetchone()[0])
    for t in type_names:
        try:
            cursor.execute(sql_select_type % t)
            if cursor.fetchone()[0] == 0:
                ticket_type_max_value += 1
                debug(env, "ticket_type '%s' not found within table 'enum' - will " \
                      "insert it with value %d..." % (t,ticket_type_max_value))
                # If the type is not present already insert with the next value available
                cursor.execute(sql_insert_type % (t, ticket_type_max_value))
                if handle_ta:
                    db.commit()
            else:
                debug(env, "Found ticket_type '%s' within table 'enum'" % (t))
        except Exception, e:
            if handle_ta:
                db.rollback()
            exception_to_unicode(e)
Пример #12
0
def create_table(env, table, conn=None):
    """
    Creates a the given table in the given environment. The Table
    has to be of type trac.db.Table, and the Environment a 
    trac.env.Environment.
    """
    assert isinstance(env, Environment), \
        "[DB]: env should be an instance of trac.env.Environment, got %s" % type(env)
    assert isinstance(table, Table), \
        "[DB]: table should be an instance of trac.sb.Table, got %s" % type(table)
    # Get The Databse Manager
    dbm = DatabaseManager(env)
    # Get the Connector Object for the current DB schema
    connector, args = dbm._get_connector()
    # Ask the connector to generate the proper DDL for the table
    ddl_gen = connector.to_sql(table)
    # Get a DB Connection from the pool, create a cursor and the table
    conn, handle_ta = get_db_for_write(env, conn)
    try:
        cursor = conn.cursor()
        for statement in ddl_gen:
            debug(env, "[DB]: Table: %s\n%s" % (table.name, statement))
            cursor.execute(statement)
        if handle_ta:
            conn.commit()
        debug(env, "[DB]: Successfully Created Table %s" % table.name)
    except Exception, e:
        if handle_ta:
            conn.rollback()
        error(env, "[DB]: Unable to Create Table %s, an error occurred: %s" % \
                    (table.name, exception_to_unicode(e)))
        raise
Пример #13
0
 def _set_duration(self, value):
     """Sets the duration of the Sprint and recalculates the end Date"""
     if value is not None:
         week_days_off = None
         if AgiloConfig(self.env).sprints_can_start_or_end_on_weekends:
             week_days_off = []
         self.end = add_to_date(self.start, value, week_days_off=week_days_off)
         debug(self, "Setting Sprint end date to: %s" % self.end)
Пример #14
0
 def _set_duration(self, value):
     """Sets the duration of the Sprint and recalculates the end Date"""
     if value is not None:
         week_days_off = None
         if AgiloConfig(self.env).sprints_can_start_or_end_on_weekends:
             week_days_off = []
         self.end = add_to_date(self.start, value, week_days_off=week_days_off)
         debug(self, "Setting Sprint end date to: %s" % self.end)
Пример #15
0
 def _add_linking_source_to_template_data(self, req, data):
     if 'src' in req.args:
         debug(self, "Got SRC: %s" % req.args['src'])
         try:
             data['src'] = int(req.args['src'])
         except (ValueError, TypeError):
             raise TracError("src (%s) must be a valid ticket id!" %
                             req.args['src'])
Пример #16
0
 def validate_rules(self, ticket):
     """
     Validates the give ticket against the registered rules. Every rule
     will be validated and has to take care of all the checks, return True
     or False
     """
     debug(self, "Called validate_rules(%s)" % ticket)
     for r in self.rules:
         r.validate(ticket)
Пример #17
0
 def validate_rules(self, ticket):
     """
     Validates the give ticket against the registered rules. Every rule
     will be validated and has to take care of all the checks, return True
     or False
     """
     debug(self, "Called validate_rules(%s)" % ticket)
     for r in self.rules:
         r.validate(ticket)
Пример #18
0
 def validate(self, ticket):
     """Accept only tickets with remaining time field"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             ticket.is_writeable_field(Key.REMAINING_TIME):
         remaining_time = ticket[Key.REMAINING_TIME] or ''
         match = self.extract_numbers_regex.match(remaining_time)
         if match != None:
             time_as_number = match.group(1)
             ticket[Key.REMAINING_TIME] = time_as_number
         else:
             ticket[Key.REMAINING_TIME] = None
Пример #19
0
 def validate(self, ticket):
     """Accept only tickets with remaining time field"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             ticket.is_writeable_field(Key.REMAINING_TIME):
         remaining_time = ticket[Key.REMAINING_TIME] or ''
         match = self.extract_numbers_regex.match(remaining_time)
         if match != None:
             time_as_number = match.group(1)
             ticket[Key.REMAINING_TIME] = time_as_number
         else:
             ticket[Key.REMAINING_TIME] = None
Пример #20
0
 def validate(self, ticket):
     """Accept tickets which have story as parents and have remaninig time"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             ticket.is_writeable_field(Key.REMAINING_TIME) and \
             ticket[Key.STATUS] == Status.ACCEPTED and \
             len(ticket.get_incoming()) > 0:
         # The ticket is a task or similar and has parents
         for p in ticket.get_incoming():
             if p.get_type() == Type.USER_STORY and \
                     p[Key.STATUS] != Status.ACCEPTED:
                 p[Key.STATUS] = Status.ACCEPTED
                 p.save_changes('agilo', 'Updated status, related task in progress')
Пример #21
0
 def validate(self, ticket):
     """Accept tickets which have story as parents and have remaninig time"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             ticket.is_writeable_field(Key.REMAINING_TIME) and \
             ticket[Key.STATUS] == Status.ACCEPTED and \
             len(ticket.get_incoming()) > 0:
         # The ticket is a task or similar and has parents
         for p in ticket.get_incoming():
             if p.get_type() == Type.USER_STORY and \
                     p[Key.STATUS] != Status.ACCEPTED:
                 p[Key.STATUS] = Status.ACCEPTED
                 p.save_changes('agilo',
                                'Updated status, related task in progress')
Пример #22
0
 def validate(self, ticket):
     """Validate the ticket against the defined rules"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             Key.REMAINING_TIME in ticket.fields_for_type:
         
         sprint_name = ticket[Key.SPRINT]
         if sprint_name not in (None, ''):
             sprint = SprintModelManager(self.env).get(name=sprint_name)
             if sprint and sprint.team is not None:
                 owner = ticket[Key.OWNER]
                 self.check_team_membership(ticket, sprint, owner, is_owner=True)
                 for r in ticket.get_resource_list():
                     self.check_team_membership(ticket, sprint, r)
Пример #23
0
 def validate(self, ticket):
     """Accept only tickets with owner and resources fields"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             Key.OWNER in ticket.fields_for_type and \
             Key.RESOURCES in ticket.fields_for_type:
         owner = ticket[Key.OWNER]
         resources = ticket.get_resource_list()
         if (owner is None or owner.strip() == '') and \
                 len(resources) > 0:
             ticket[Key.OWNER] = resources[0]
             ticket[Key.RESOURCES] = ', '.join([r.strip() for r in resources[1:] if r.strip() != ''])
         elif owner is not None and owner.strip() in resources:
             resources.remove(owner.strip())
             ticket[Key.RESOURCES] = ', '.join([r.strip() for r in resources if r.strip() != ''])
Пример #24
0
 def create_permissions(self, req):
     """
     Returns a list of the permissions to create new ticket types for the
     given request object
     """
     create_perms = list()
     # see what ticket types the user has create permissions for
     for t_type, alias in AgiloConfig(self.env).ALIASES.items():
         permission_name = self.get_permission_name_to_create(t_type)
         debug(self, "Type: %s, Alias: %s Permission: %s" % \
               (t_type, alias, permission_name))
         if permission_name in req.perm:
             create_perms.append(t_type)
     debug(self, "%s has create permission for types: %s" % \
                 (req.authname, create_perms))
     return create_perms
Пример #25
0
 def create_permissions(self, req):
     """
     Returns a list of the permissions to create new ticket types for the
     given request object
     """
     create_perms = list()
     # see what ticket types the user has create permissions for
     for t_type, alias in AgiloConfig(self.env).ALIASES.items():
         permission_name = self.get_permission_name_to_create(t_type)
         debug(self, "Type: %s, Alias: %s Permission: %s" % \
               (t_type, alias, permission_name))
         if permission_name in req.perm:
             create_perms.append(t_type)
     debug(self, "%s has create permission for types: %s" % \
                 (req.authname, create_perms))
     return create_perms
Пример #26
0
 def _display_back_to_url(self, req):
     """
     Check in the session for a back_to_url link to visualize in 
     the Jump Back
     """
     back_to_key = 'back_to_url'
     
     back_to_url = None
     if req.args.has_key(back_to_key):
         back_to_url = req.args.get(back_to_key)
     elif req.session.has_key(back_to_key):
         back_to_url = req.session.get(back_to_key)
         
     debug(self, "$$$ VALUE OF back_to_url: %s $$$" % back_to_url)
     if back_to_url is not None:
         # Add it directly to the context navigation bar
         add_ctxtnav(req, _('Jump Back'), back_to_url)
Пример #27
0
    def validate(self, ticket):
        """Validate the ticket against the defined rules"""
        debug(self, "Called validate(%s)..." % ticket)
        if ticket is not None and isinstance(ticket, AgiloTicket) and \
                Key.REMAINING_TIME in ticket.fields_for_type:

            sprint_name = ticket[Key.SPRINT]
            if sprint_name not in (None, ''):
                sprint = SprintModelManager(self.env).get(name=sprint_name)
                if sprint and sprint.team is not None:
                    owner = ticket[Key.OWNER]
                    self.check_team_membership(ticket,
                                               sprint,
                                               owner,
                                               is_owner=True)
                    for r in ticket.get_resource_list():
                        self.check_team_membership(ticket, sprint, r)
Пример #28
0
 def _extract_params(self, req):
     # This will give priority to a rename in case of change
     name = req.args.get('name')
     if name is None:
         name = req.args.get('sprint_name')
     milestone = req.args.get('milestone') or req.args.get('url_milestone')
     action = req.args.get('edit') or req.args.get('add')
     log.debug(self, "Processing request: action:%s name:%s milestone:%s" % \
           (action, name, milestone))
     if action == 'edit':
         if not name:
             raise TracError(_("Please provide a Sprint Name"))
         elif 'save' in req.args and not milestone:
             raise TracError(_("Please provide a Milestone Name"))
     elif action == 'add' and not milestone:
         raise TracError(_("Please provide a Milestone Name"))
     return name, milestone, action
Пример #29
0
    def _display_back_to_url(self, req):
        """
        Check in the session for a back_to_url link to visualize in 
        the Jump Back
        """
        back_to_key = 'back_to_url'

        back_to_url = None
        if req.args.has_key(back_to_key):
            back_to_url = req.args.get(back_to_key)
        elif req.session.has_key(back_to_key):
            back_to_url = req.session.get(back_to_key)

        debug(self, "$$$ VALUE OF back_to_url: %s $$$" % back_to_url)
        if back_to_url is not None:
            # Add it directly to the context navigation bar
            add_ctxtnav(req, _('Jump Back'), back_to_url)
Пример #30
0
 def _extract_params(self, req):
     # This will give priority to a rename in case of change
     name = req.args.get('name')
     if name is None:
         name = req.args.get('sprint_name')
     milestone = req.args.get('milestone') or req.args.get('url_milestone')
     action = req.args.get('edit') or req.args.get('add')
     log.debug(self, "Processing request: action:%s name:%s milestone:%s" % \
           (action, name, milestone))
     if action == 'edit':
         if not name:
             raise TracError(_("Please provide a Sprint Name"))
         elif 'save' in req.args and not milestone:
             raise TracError(_("Please provide a Milestone Name"))
     elif action == 'add' and not milestone:
         raise TracError(_("Please provide a Milestone Name"))
     return name, milestone, action
Пример #31
0
 def validate(self, ticket):
     """Accept only tickets with owner and resources fields"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             Key.OWNER in ticket.fields_for_type and \
             Key.RESOURCES in ticket.fields_for_type:
         owner = ticket[Key.OWNER]
         resources = ticket.get_resource_list()
         if (owner is None or owner.strip() == '') and \
                 len(resources) > 0:
             ticket[Key.OWNER] = resources[0]
             ticket[Key.RESOURCES] = ', '.join(
                 [r.strip() for r in resources[1:] if r.strip() != ''])
         elif owner is not None and owner.strip() in resources:
             resources.remove(owner.strip())
             ticket[Key.RESOURCES] = ', '.join(
                 [r.strip() for r in resources if r.strip() != ''])
Пример #32
0
 def ticket_changed(self, ticket, comment, author, old_values):
     """Called when a ticket is modified.
     `old_values` is a dictionary containing the previous values of the
     fields that have changed.
     """
     debug(self, "Invoked for ticket #%s of type %s" % \
                  (ticket.id, ticket[Key.TYPE]))
     if Key.REMAINING_TIME in old_values:
         # remaining time has been changed
         previous_remaining_time = old_values.get(Key.REMAINING_TIME)
         ticket_remaining = float(ticket[Key.REMAINING_TIME] or '0')
     
         if previous_remaining_time != ticket_remaining:
             rt = RemainingTime(self.env, ticket)
             rt.set_remaining_time(ticket_remaining)
             debug(self, "Updated remaining_time for ticket #%s from: %s to %s" % \
                   (ticket, previous_remaining_time, ticket_remaining))
Пример #33
0
 def validate(self, ticket):
     """Accepts only tickets with remaining_time field"""
     debug(self, "Called validate(%s)..." % ticket)
     if ticket is not None and isinstance(ticket, AgiloTicket) and \
             ticket.is_writeable_field(Key.REMAINING_TIME):
         
         remaining_time = self.parse_remaining_time(ticket)
         if (not self.status_did_change(ticket)) and (not self.remaining_time_did_change(ticket)):
             return
         elif remaining_time is None:
             return
         
         ticket_was_closed = (self.old_status(ticket) == Status.CLOSED)
         ticket_is_now_closed = (ticket[Key.STATUS] == Status.CLOSED)
         if self.status_did_change(ticket) and ticket_is_now_closed and remaining_time != 0:
             ticket[Key.REMAINING_TIME] = '0'
         elif self.remaining_time_did_change(ticket) and (not ticket_was_closed) and remaining_time == 0:
             ticket[Key.STATUS] = Status.CLOSED
             ticket[Key.RESOLUTION] = Status.RES_FIXED
Пример #34
0
 def _load(self, db=None):
     """Try to load the Sprint from the database"""
     db, handle_ta = get_db_for_write(self.env, db)
     sql_query = "SELECT date, remaining_time FROM %s" \
                 " WHERE task_id=%d ORDER BY date DESC" % (BURNDOWN_TABLE, self.task.id)
     debug(self, "Burndown-SQL Query: %s" % sql_query)
     try:
         history = dict()
         cursor = db.cursor()
         cursor.execute(sql_query)
         for row in cursor.fetchall():
             timestamp, remaining_time = row
             history[timestamp] = remaining_time
         
         self.loaded = True
     except Exception, e:
         error(self, to_unicode(e))
         if handle_ta:
             db.rollback()
         raise TracError("An error occurred while loading Burndown data: %s" % to_unicode(e))
Пример #35
0
 def expand_macro(self, formatter, name, content):
     req = formatter.req
     # Analyze the arguments list, that should be in content
     args = content.split(',')
     if len(args) == 0:
         raise TracError("No argument provided for %s." % self.__class__.__name__)
     
     # The first must be the type of the chart
     chart_type = self._get_chart_type(args[0])
     # The second the Sprint
     sprint_name = self._get_sprint(args[1])
     width, height = self._get_dimensions(args[2:])
     filter_by = None
     if len(args) >= 4:
         filter_by = args[3]
     
     chart_params = dict(sprint_name=sprint_name, width=width, height=height, 
                         filter_by=filter_by)
     debug(self.env, "Params: %s" % chart_params)
     chart = ChartGenerator(self.env).get_chartwidget(chart_type, **chart_params)
     chart.prepare_rendering(req)
     return html.DIV(chart.display())
Пример #36
0
    def validate(self, ticket):
        """Accepts only tickets with remaining_time field"""
        debug(self, "Called validate(%s)..." % ticket)
        if ticket is not None and isinstance(ticket, AgiloTicket) and \
                ticket.is_writeable_field(Key.REMAINING_TIME):

            remaining_time = self.parse_remaining_time(ticket)
            if (not self.status_did_change(ticket)) and (
                    not self.remaining_time_did_change(ticket)):
                return
            elif remaining_time is None:
                return

            ticket_was_closed = (self.old_status(ticket) == Status.CLOSED)
            ticket_is_now_closed = (ticket[Key.STATUS] == Status.CLOSED)
            if self.status_did_change(
                    ticket) and ticket_is_now_closed and remaining_time != 0:
                ticket[Key.REMAINING_TIME] = '0'
            elif self.remaining_time_did_change(ticket) and (
                    not ticket_was_closed) and remaining_time == 0:
                ticket[Key.STATUS] = Status.CLOSED
                ticket[Key.RESOLUTION] = Status.RES_FIXED
Пример #37
0
 def _fetch_tickets(self, db=None):
     """
     Fetch from the DB the ids, type, status of the tickets planned for this sprint,
     and returns a list of id, type, status.
     """
     params = {'table': BACKLOG_TICKET_TABLE, 'scope': self.name}
     t_sql = "SELECT DISTINCT id, type, status FROM ticket INNER JOIN ticket_custom ON "\
             "ticket.id=ticket_custom.ticket LEFT OUTER JOIN %(table)s ON " \
             "ticket.id=%(table)s.ticket_id WHERE (%(table)s.name='Sprint Backlog' " \
             "AND scope='%(scope)s') or (ticket_custom.name='sprint' AND " \
             "ticket_custom.value='%(scope)s')" % params
     
     tickets = [(0, '', '')]
     
     db, handle_ta = get_db_for_write(self.env, db)
     try:
         cursor = db.cursor()
         debug(self, "SQL (_fetch_tickets_stats): %s" % t_sql)
         cursor.execute(t_sql)
         tickets = cursor.fetchall()
     except:
         if handle_ta:
             db.rollback()
     return tickets
Пример #38
0
    def _rename(self, name, new_name, db=None):
        """Renames this sprint and reassigns all tickets to the new 
        name."""
        # avoid circular imports
        from agilo.scrum.metrics.model import TeamMetrics

        params = {"name": name, "new_name": new_name}
        team_metrics_entry_table = TeamMetrics.TeamMetricsEntry._table.name
        queries = [
            "UPDATE ticket_custom SET value=%(new_name)s WHERE name='sprint' AND value=%(name)s",
            "UPDATE " + team_metrics_entry_table + " SET sprint=%(new_name)s WHERE sprint=%(name)s",
        ]
        db, handle_ta = get_db_for_write(self.env, db)
        try:
            cursor = db.cursor()
            for q in queries:
                debug(self, "RENAME => Executing query: %s (%s)" % (q, params))
                safe_execute(cursor, q, params)
            if handle_ta:
                db.commit()
        except Exception, e:
            if handle_ta:
                db.rollback()
            raise TracError("An error occurred while renaming sprint: %s" % to_unicode(e))
Пример #39
0
    def get_tickets_matching(self, t_id, summary):
        """
        Returns a list of dictionaries (id: value, summary: value) matching the summary 
        request and excluding the requesting ticket having id = id.
        """
        try:
            t_id = int(t_id)  # Make sure it is an int :-)
            keyword = re.compile(summary, re.IGNORECASE)
            db = self.env.get_db_cnx()

            from agilo.ticket.model import AgiloTicketModelManager
            sql = """SELECT id, type, summary FROM ticket WHERE id != $id $allowed 
                  AND id NOT IN (SELECT dest FROM %s WHERE src = $id UNION
                  SELECT src FROM %s WHERE dest = $id) ORDER BY summary""" \
                    % (LINKS_TABLE, LINKS_TABLE)
            sql_query = string.Template(sql)
            sql_allowed = "AND ticket.type IN ('%s')"
            t_type = AgiloTicketModelManager(
                self.env).get(tkt_id=t_id).get_type()
            linkconfig = LinksConfiguration(self.env)
            if linkconfig.is_allowed_source_type(t_type):
                allowed_types = linkconfig.get_allowed_destination_types(
                    t_type)
                allowed = sql_allowed % '\', \''.join(allowed_types)
            else:
                debug(self, "No Key found for #%s#" % repr(t_type))
                allowed = ''

            sql_query = sql_query.substitute({'id': t_id, 'allowed': allowed})
            debug(self, "SQL: %s" % sql_query)
            cursor = db.cursor()
            cursor.execute(sql_query)

            results = []
            for row in cursor:
                if keyword.search(row[2] or ''):
                    results.append({
                        'id': row[0],
                        'type': row[1],
                        'summary': row[2]
                    })

            debug(self, "Search Results: %s" % str(results))
            return results

        except Exception, e:
            warning(self, e)
            msg = "[%s]: ERROR: Search module unable to complete query!" % \
                    self.__class__.__name__
            raise TracError(msg)
Пример #40
0
 def get_tickets_matching(self, t_id, summary):
     """
     Returns a list of dictionaries (id: value, summary: value) matching the summary 
     request and excluding the requesting ticket having id = id.
     """
     try:
         t_id = int(t_id) # Make sure it is an int :-)
         keyword = re.compile(summary, re.IGNORECASE)
         db = self.env.get_db_cnx()
         
         from agilo.ticket.model import AgiloTicketModelManager
         sql = """SELECT id, type, summary FROM ticket WHERE id != $id $allowed 
               AND id NOT IN (SELECT dest FROM %s WHERE src = $id UNION
               SELECT src FROM %s WHERE dest = $id) ORDER BY summary""" \
                 % (LINKS_TABLE, LINKS_TABLE)
         sql_query = string.Template(sql)
         sql_allowed = "AND ticket.type IN ('%s')"
         t_type = AgiloTicketModelManager(self.env).get(tkt_id=t_id).get_type()
         linkconfig = LinksConfiguration(self.env)
         if linkconfig.is_allowed_source_type(t_type):
             allowed_types = linkconfig.get_allowed_destination_types(t_type)
             allowed = sql_allowed % '\', \''.join(allowed_types)
         else:
             debug(self, "No Key found for #%s#" % repr(t_type))
             allowed = ''
                 
         sql_query = sql_query.substitute({'id' : t_id, 'allowed' : allowed})
         debug(self, "SQL: %s" % sql_query)
         cursor = db.cursor()
         cursor.execute(sql_query)
         
         results = []
         for row in cursor:
             if keyword.search(row[2] or ''):
                 results.append({'id': row[0], 'type': row[1], 
                                 'summary': row[2]})  
         
         debug(self, "Search Results: %s" % str(results))
         return results
         
     except Exception, e:
         warning(self, e)
         msg = "[%s]: ERROR: Search module unable to complete query!" % \
                 self.__class__.__name__
         raise TracError(msg) 
Пример #41
0
 def _get_duration(self):
     """Gets the duration of the Sprint"""
     duration = count_working_days(self.start, self.end)
     debug(self, "Returning duration %d start: %s, end: %s" % (duration, self.start, self.end))
     return duration
Пример #42
0
 def _get_duration(self):
     """Gets the duration of the Sprint"""
     duration = count_working_days(self.start, self.end)
     debug(self, "Returning duration %d start: %s, end: %s" % \
                 (duration, self.start, self.end))
     return duration