예제 #1
0
    def filter_stream(self, req, method, filename, stream, data):
        chrome = Chrome(self.env)

        if req.path_info.startswith('/milestone') \
            and req.args.get('action') in ['edit', 'new'] \
            and 'max_level' not in data:
            milestone = data.get('milestone')
            levels = IttecoMilestoneAdminPanel(self.env).milestone_levels
            mydata ={'structured_milestones':StructuredMilestone.select(self.env),
                  'max_level':  levels and len(levels)-1 or 0,
                  'milestone_name' : milestone and milestone.parent or None,
                  'field_name' : 'parent'}
            stream |=Transformer('//*[@id="edit"]/fieldset').append(
                chrome.render_template(req, 'itteco_milestones_dd.html', mydata, fragment=True))
            
        if 'ticket' in data:
            tkt = data['ticket']
            mydata ={
                'structured_milestones':StructuredMilestone.select(self.env),
                'milestone_name': data['ticket']['milestone'],
                'field_name' : 'field_milestone',
                'hide_completed' : not ( tkt.exists and 'TICKET_ADMIN' in req.perm(tkt.resource))
            }
            req.chrome.setdefault('ctxtnav',[]).insert(
                -1, 
                tag.a(
                    _('Go To Whiteboard'), 
                    href=req.href.whiteboard('team_tasks', data['ticket']['milestone'] or 'none')
                )
            )
            stream |=Transformer('//*[@id="field-milestone"]').replace(
                chrome.render_template(req, 'itteco_milestones_dd.html', mydata, fragment=True))
        return stream
예제 #2
0
    def _render_editor(self, req, db, milestone):
        data = {
            'milestone': milestone,
            'ticket': milestone.ticket,
            'datefields' : self.date_fields,
            'date_hint': get_date_format_hint(),
            'datetime_hint': get_datetime_format_hint(),
            'milestone_groups': [],
            'jump_to' : req.args.get('jump_to') or referer_module(req)
        }

        if milestone.exists:
            req.perm(milestone.resource).require('MILESTONE_VIEW')
            milestones = [m for m in StructuredMilestone.select(self.env, db=db)
                          if m.name != milestone.name
                          and 'MILESTONE_VIEW' in req.perm(m.resource)]
            data['milestone_groups'] = group_milestones(milestones,
                'TICKET_ADMIN' in req.perm)
        else:
            req.perm(milestone.resource).require('MILESTONE_CREATE')

        TicketModule(self.env)._insert_ticket_data(req, milestone.ticket, data, 
                                         get_reporter_id(req, 'author'), {})
        self._add_tickets_report_data(milestone, req, data)
        context = Context.from_request(req, milestone.resource)
        
        data['attachments']=AttachmentModule(self.env).attachment_data(context)

        return 'itteco_milestone_edit.html', data, None
예제 #3
0
 def _resolve_milestone(self, name, include_kids, show_completed):
     def _flatten_and_get_names(mil, include_kids, show_completed):
         names= []
         if mil:
             mil = isinstance(mil, StructuredMilestone) and [mil,] or mil
             for m in mil:
                 if show_completed or not m.completed:
                     names.append(m.name)
                     if include_kids:
                         names.extend(_flatten_and_get_names(m.kids, include_kids, show_completed))
         return names
     if name=='nearest':
         db = self.env.get_db_cnx()
         cursor = db.cursor()
         cursor.execute(
             'SELECT name FROM milestone WHERE due>%s ORDER BY due LIMIT 1', \
             (to_timestamp(datetime.now(utc)),))
         row = cursor.fetchone()
         name=row and row[0] or 'none'
     elif name=='not_completed_milestones':
         return _flatten_and_get_names(StructuredMilestone.select(self.env, False), \
             include_kids, show_completed)
     if name=='none':
         return ''
     try:    
         mil = StructuredMilestone(self.env, name)            
         names = _flatten_and_get_names(mil, include_kids, show_completed)
         if not names:
             names = mil.name
         return names
     except ResourceNotFound:
         return ''
예제 #4
0
    def _render_editor(self, req, db, milestone):
        data = {
            'milestone': milestone,
            'ticket': milestone.ticket,
            'datefields': self.date_fields,
            'date_hint': get_date_format_hint(),
            'datetime_hint': get_datetime_format_hint(),
            'milestone_groups': [],
            'jump_to': req.args.get('jump_to') or referer_module(req)
        }

        if milestone.exists:
            req.perm(milestone.resource).require('MILESTONE_VIEW')
            milestones = [
                m for m in StructuredMilestone.select(self.env, db=db)
                if m.name != milestone.name
                and 'MILESTONE_VIEW' in req.perm(m.resource)
            ]
            data['milestone_groups'] = group_milestones(
                milestones, 'TICKET_ADMIN' in req.perm)
        else:
            req.perm(milestone.resource).require('MILESTONE_CREATE')

        TicketModule(self.env)._insert_ticket_data(
            req, milestone.ticket, data, get_reporter_id(req, 'author'), {})
        self._add_tickets_report_data(milestone, req, data)
        context = Context.from_request(req, milestone.resource)

        data['attachments'] = AttachmentModule(
            self.env).attachment_data(context)

        return 'itteco_milestone_edit.html', data, None
예제 #5
0
    def filter_stream(self, req, method, filename, stream, data):
        chrome = Chrome(self.env)

        if req.path_info.startswith('/milestone') \
            and req.args.get('action') in ['edit', 'new'] \
            and 'max_level' not in data:
            milestone = data.get('milestone')
            levels = IttecoMilestoneAdminPanel(self.env).milestone_levels
            mydata = {
                'structured_milestones': StructuredMilestone.select(self.env),
                'max_level': levels and len(levels) - 1 or 0,
                'milestone_name': milestone and milestone.parent or None,
                'field_name': 'parent'
            }
            stream |= Transformer('//*[@id="edit"]/fieldset').append(
                chrome.render_template(req,
                                       'itteco_milestones_dd.html',
                                       mydata,
                                       fragment=True))

        if 'ticket' in data:
            tkt = data['ticket']
            mydata = {
                'structured_milestones':
                StructuredMilestone.select(self.env),
                'milestone_name':
                data['ticket']['milestone'],
                'field_name':
                'field_milestone',
                'hide_completed':
                not (tkt.exists and 'TICKET_ADMIN' in req.perm(tkt.resource))
            }
            req.chrome.setdefault('ctxtnav', []).insert(
                -1,
                tag.a(_('Go To Whiteboard'),
                      href=req.href.whiteboard(
                          'team_tasks', data['ticket']['milestone']
                          or 'none')))
            stream |= Transformer('//*[@id="field-milestone"]').replace(
                chrome.render_template(req,
                                       'itteco_milestones_dd.html',
                                       mydata,
                                       fragment=True))
        return stream
예제 #6
0
    def process_request(self, req):
        req.perm('ticket').require('TICKET_VIEW')
        
        board_type = req.args.get('board_type', 'team_tasks')
        milestone = req.args.get('milestone')
        if board_type == 'chart_settings':
            return self._chart_settings(milestone)
        else:
            board_type = _get_req_param(req, 'board_type', 'team_tasks')
            
            if board_type != req.args.get('board_type'):
                #boardtype was not implicitly  selected, let's restore previos state
                req.redirect(req.href.whiteboard(board_type, milestone))

            add_stylesheet(req, 'common/css/roadmap.css')
            add_stylesheet(req, 'itteco/css/common.css')            
            add_jscript(
                req, 
                [
                    'stuff/ui/ui.core.js',
                    'stuff/ui/ui.draggable.js',
                    'stuff/ui/ui.droppable.js',
                    'stuff/ui/ui.resizable.js',
                    'stuff/ui/plugins/jquery.colorbox.js',
                    'stuff/plugins/jquery.rpc.js',
                    'custom_select.js',
                    'whiteboard2.js'
                ],
                IttecoEvnSetup(self.env).debug
            )
            show_closed_milestones = req.args.get('show_closed_milestones', False)
            
            scope_item, work_item = self._get_wbitems_config(board_type)
            structured_milestones = StructuredMilestone.select(self.env, show_closed_milestones)
            if board_type == 'burndown':
                structured_milestones, _ignore = self._get_milestones_by_level(structured_milestones, 'Sprint', True)
            data ={
                'structured_milestones' : structured_milestones,
                'current_board_type' : board_type,
                'milestone' : milestone,
                'milestone_levels': IttecoEvnSetup(self.env).milestone_levels,
                'stats_config': self._get_stats_config(),
                'show_closed_milestones': show_closed_milestones,
                'wbconfig' : {
                    'rpcurl' : req.href.login("xmlrpc"),
                    'baseurl' : req.href(),
                    'workitem' : work_item,
                    'scopeitem': scope_item,
                    'groups': self.ticket_groups,
                    'transitions': self.transitions
                },
                'team' : self.team_members_provider and self.team_members_provider.get_team_members() or [],
                'ticket_types' : work_item['types'] or []
            }
                
            return 'itteco_whiteboard2.html', data, 'text/html'
예제 #7
0
    def ticket(self, req):
        tkt_id = req.args.get("obj_id")
        if tkt_id:
            req.perm.require("TICKET_MODIFY", Resource("ticket", tkt_id))
        else:
            req.perm.require("TICKET_CREATE")

        descriptor = WhiteboardModule(self.env).get_new_ticket_descriptor(
            [type.name for type in Type.select(self.env)], tkt_id
        )

        data = {
            "structured_milestones": StructuredMilestone.select(self.env),
            "resolutions": [],  # val.name for val in Resolution.select(self.env)],
            "new_ticket_descriptor": descriptor,
            "action_controls": self._get_action_controls(req, descriptor["ticket"]),
        }
        return "itteco_ticket_edit.html", data, "text/html"
예제 #8
0
    def milestone(self, req):
        mil_id = req.args.get("obj_id")
        if mil_id:
            req.perm.require("MILESTONE_MODIFY", Resource("milestone", mil_id))
        else:
            req.perm.require("MILESTONE_CREATE")

        milestone = StructuredMilestone(self.env, mil_id)
        descriptor = WhiteboardModule(self.env).get_new_ticket_descriptor(
            [type.name for type in Type.select(self.env)], milestone.ticket.id
        )

        data = {
            "structured_milestones": StructuredMilestone.select(self.env),
            "new_ticket_descriptor": descriptor,
            "milestone": milestone,
            "action_controls": self._get_action_controls(req, descriptor["ticket"]),
        }
        return "itteco_milestone_quick_edit.html", data, "text/html"
예제 #9
0
    def ticket(self, req):
        tkt_id = req.args.get('obj_id')
        if tkt_id:
            req.perm.require('TICKET_MODIFY', Resource('ticket', tkt_id))
        else:
            req.perm.require('TICKET_CREATE')

        descriptor = WhiteboardModule(self.env).get_new_ticket_descriptor(
            [type.name for type in Type.select(self.env)], tkt_id)

        data = {
            'structured_milestones':
            StructuredMilestone.select(self.env),
            'resolutions':
            [],  #val.name for val in Resolution.select(self.env)],
            'new_ticket_descriptor':
            descriptor,
            'action_controls':
            self._get_action_controls(req, descriptor['ticket']),
        }
        return 'itteco_ticket_edit.html', data, 'text/html'
예제 #10
0
    def milestone(self, req):
        mil_id = req.args.get('obj_id')
        if mil_id:
            req.perm.require('MILESTONE_MODIFY', Resource('milestone', mil_id))
        else:
            req.perm.require('MILESTONE_CREATE')

        milestone = StructuredMilestone(self.env, mil_id)
        descriptor = WhiteboardModule(self.env).get_new_ticket_descriptor(
            [type.name for type in Type.select(self.env)], milestone.ticket.id)

        data = {
            'structured_milestones':
            StructuredMilestone.select(self.env),
            'new_ticket_descriptor':
            descriptor,
            'milestone':
            milestone,
            'action_controls':
            self._get_action_controls(req, descriptor['ticket']),
        }
        return 'itteco_milestone_quick_edit.html', data, 'text/html'
예제 #11
0
    def query_stories(self, req, context):
        level = context.get('level')
        
        all_milestones = StructuredMilestone.select(self.env, True)
        mils, mils_dict = self._get_milestones_by_level(all_milestones, level, context.get('show_completed'))
        milestones = [mil.name for mil in mils] +['']
        fields = [
            'summary', 
            'description',
            'owner',
            self.scope_element_weight_field, 
            self.work_element_weight_field
        ]

        def milestone_as_dict(milestone):
            res = dict([(f, milestone.ticket[f]) for f in fields])
            res.update(
                {
                    'id': milestone.name,
                    'references': []
                }
            )
            return res
        empty_scope_element  = {'id': '', 'summary': 'Backlog (no milestone)','references': []}
        
        roots = [empty_scope_element] + [milestone_as_dict(m) for m in mils]
        milestone_by_name = dict([(m['id'], m) for m in roots])
       
        scope_tkt_types = set([t for t in IttecoEvnSetup(self.env).scope_element])       
        tickets, ticket_ids = self._get_tickets_graph(req, milestones, (scope_tkt_types,))
        
        self.env.log.debug('roots ="%s"' % (roots,))
        for ticket in tickets:
            root = milestone_by_name.get(ticket['milestone'],empty_scope_element)
            root['references'].append(ticket)
            
        return roots
예제 #12
0
    def process_request(self, req):
        milestone_realm = Resource('milestone')
        req.perm.require('MILESTONE_VIEW')

        showall = req.args.get('show') == 'all'
        db = self.env.get_db_cnx()
        milestones = [m for m in StructuredMilestone.select(self.env, True, db)
                        if 'MILESTONE_VIEW' in req.perm(m.resource)]
        requested_fmt = req.args.get('format')
        if requested_fmt == 'ics':
            self.render_ics(req, db, milestones)
            return
        max_level = len(IttecoEvnSetup(self.env).milestone_levels)
        max_level = max_level and max_level-1 or 0;
        current_level = int(req.args.get('mil_type', max_level))
        
        if current_level==-1:
            #show all milestones regardless to the level
            milestones = sum([_get_milestone_with_all_kids(mil) for mil in milestones], [])
        else:
            #filter by level
            i =0        
            while i<current_level:
                next_level_mils = []
                for m in milestones:
                    next_level_mils.extend(m.kids)
                milestones = next_level_mils
                i+=1

        calc_on = req.args.get('calc_on')
        ticket_group = req.args.get('ticket_group', 'all')
        selected_types = None
        if ticket_group=='scope_element':
            selected_types = IttecoEvnSetup(self.env).scope_element
        elif ticket_group=='work_element':
            selected_types = IttecoEvnSetup(self.env).work_element
        else:
            ticket_group = 'all'
            
        selected_type_names = [tkt_type.name for tkt_type in Type.select(self.env) 
            if selected_types is None or tkt_type.value in selected_types]

        stats = []
        milestones = [mil for mil in milestones if showall or not mil.is_completed]
        for milestone in milestones:
            tickets = get_tickets_for_structured_milestone(
                self.env, db, milestone.name, calc_on, selected_type_names)
            tickets = apply_ticket_permissions(self.env, req, tickets)
            stat = SelectionTicketGroupStatsProvider(self.env).get_ticket_group_stats(tickets, calc_on)
            stats.append(
                milestone_stats_data(
                    req, stat, [m.name for m in _get_milestone_with_all_kids(milestone)]))

        if requested_fmt=='json':
            self._render_milestones_stats_as_json(req, milestones, stats)
            return
        # FIXME should use the 'webcal:' scheme, probably
        username = None
        if req.authname and req.authname != 'anonymous':
            username = req.authname
        icshref = req.href.roadmap(show=req.args.get('show'), user=username,
                                   format='ics')
        add_link(req, 'alternate', icshref, _('iCalendar'), 'text/calendar',
                 'ics')
        visibility = [{'index':idx, 'label': label, 'active': idx==current_level} 
            for idx, label in enumerate(IttecoEvnSetup(self.env).milestone_levels)]
        ticket_groups = [{'index':value, 'label': name, 'active': value==ticket_group} 
                for value, name in self._ticket_groups]
        
        calculate_on = self.get_statistics_source(req.args.get('calc_on'))
        data = {
            'milestones': milestones,
            'milestone_stats': stats,
            'mil_types': visibility,
            'ticket_groups': ticket_groups,
            'calc_on': calculate_on,
            'queries': [],
            'showall': showall,
        }
        self.env.log.debug('data:%s' % data)
        return 'itteco_roadmap.html', data, None
예제 #13
0
    def process_request(self, req):
        milestone_realm = Resource('milestone')
        req.perm.require('MILESTONE_VIEW')

        showall = req.args.get('show') == 'all'
        db = self.env.get_db_cnx()
        milestones = [
            m for m in StructuredMilestone.select(self.env, True, db)
            if 'MILESTONE_VIEW' in req.perm(m.resource)
        ]
        requested_fmt = req.args.get('format')
        if requested_fmt == 'ics':
            self.render_ics(req, db, milestones)
            return
        max_level = len(IttecoEvnSetup(self.env).milestone_levels)
        max_level = max_level and max_level - 1 or 0
        current_level = int(req.args.get('mil_type', max_level))

        if current_level == -1:
            #show all milestones regardless to the level
            milestones = sum(
                [_get_milestone_with_all_kids(mil) for mil in milestones], [])
        else:
            #filter by level
            i = 0
            while i < current_level:
                next_level_mils = []
                for m in milestones:
                    next_level_mils.extend(m.kids)
                milestones = next_level_mils
                i += 1

        calc_on = req.args.get('calc_on')
        ticket_group = req.args.get('ticket_group', 'all')
        selected_types = None
        if ticket_group == 'scope_element':
            selected_types = IttecoEvnSetup(self.env).scope_element
        elif ticket_group == 'work_element':
            selected_types = IttecoEvnSetup(self.env).work_element
        else:
            ticket_group = 'all'

        selected_type_names = [
            tkt_type.name for tkt_type in Type.select(self.env)
            if selected_types is None or tkt_type.value in selected_types
        ]

        stats = []
        milestones = [
            mil for mil in milestones if showall or not mil.is_completed
        ]
        for milestone in milestones:
            tickets = get_tickets_for_structured_milestone(
                self.env, db, milestone.name, calc_on, selected_type_names)
            tickets = apply_ticket_permissions(self.env, req, tickets)
            stat = SelectionTicketGroupStatsProvider(
                self.env).get_ticket_group_stats(tickets, calc_on)
            stats.append(
                milestone_stats_data(
                    req, stat,
                    [m.name for m in _get_milestone_with_all_kids(milestone)]))

        if requested_fmt == 'json':
            self._render_milestones_stats_as_json(req, milestones, stats)
            return
        # FIXME should use the 'webcal:' scheme, probably
        username = None
        if req.authname and req.authname != 'anonymous':
            username = req.authname
        icshref = req.href.roadmap(show=req.args.get('show'),
                                   user=username,
                                   format='ics')
        add_link(req, 'alternate', icshref, _('iCalendar'), 'text/calendar',
                 'ics')
        visibility = [{
            'index': idx,
            'label': label,
            'active': idx == current_level
        } for idx, label in enumerate(
            IttecoEvnSetup(self.env).milestone_levels)]
        ticket_groups = [{
            'index': value,
            'label': name,
            'active': value == ticket_group
        } for value, name in self._ticket_groups]

        calculate_on = self.get_statistics_source(req.args.get('calc_on'))
        data = {
            'milestones': milestones,
            'milestone_stats': stats,
            'mil_types': visibility,
            'ticket_groups': ticket_groups,
            'calc_on': calculate_on,
            'queries': [],
            'showall': showall,
        }
        self.env.log.debug('data:%s' % data)
        return 'itteco_roadmap.html', data, None
예제 #14
0
    def _render_admin_panel(self, req, cat, page, milestone):
        req.perm.require('TICKET_ADMIN')
        add_stylesheet(req, 'itteco/css/common.css')
        add_jscript(
            req, 
            [
                'stuff/ui/ui.core.js',
                'stuff/ui/ui.resizable.js',
                'custom_select.js'
            ],
            IttecoEvnSetup(self.env).debug
        )
        # Detail view?
        if milestone:
            mil = StructuredMilestone(self.env, milestone)
            if req.method == 'POST':
                if req.args.get('save'):
                    mil.name = req.args.get('name')
                    mil.due = mil.completed = None
                    due = req.args.get('duedate', '')
                    if due:
                        mil.due = parse_date(due, req.tz)
                    if req.args.get('completed', False):
                        completed = req.args.get('completeddate', '')
                        mil.completed = parse_date(completed, req.tz)
                        if mil.completed > datetime.now(utc):
                            raise TracError(_('Completion date may not be in '
                                              'the future'),
                                            _('Invalid Completion Date'))
                    mil.description = req.args.get('description', '')
                    mil.parent = req.args.get('parent', None)
                    if mil.parent and mil.parent==mil.name:
                        raise TracError(_('Milestone cannot be parent for itself,Please, give it another thought.'),
                                        _('Something is wrong with Parent Milestone. Will you check it please?'))

                    if mil.parent and not StructuredMilestone(self.env, mil.parent).exists:
                        raise TracError(_('Milestone should have a valid parent. It does not look like this is the case.'),
                                        _('Something is wrong with Parent Milestone. Will you check it please?'))
                    mil.update()
                    req.redirect(req.href.admin(cat, page))
                elif req.args.get('cancel'):
                    req.redirect(req.href.admin(cat, page))

            add_script(req, 'common/js/wikitoolbar.js')
            data = {'view': 'detail', 'milestone': mil}

        else:
            if req.method == 'POST':
                # Add Milestone
                if req.args.get('add') and req.args.get('name'):
                    name = req.args.get('name')
                    try:
                        StructuredMilestone(self.env, name)
                    except ResourceNotFound:
                        mil = StructuredMilestone(self.env)
                        mil.name = name
                        if req.args.get('duedate'):
                            mil.due = parse_date(req.args.get('duedate'),
                                                 req.tz)
                        mil.parent = req.args.get('parent', None)
                        if mil.parent and not StructuredMilestone(self.env, mil.parent).exists:
                            raise TracError(_('Milestone should have a valid parent. It does not look like this is the case'),
                                            _('Something is wrong with Parent Milestone. Will you check it please?'))

                        mil.insert()
                        req.redirect(req.href.admin(cat, page))
                    else:
                        raise TracError(_('Sorry, milestone %s already exists.') % name)

                # Remove milestone
                elif req.args.get('remove'):
                    sel = req.args.get('sel')
                    if not sel:
                        raise TracError(_('Please, select the milestone.'))
                    if not isinstance(sel, list):
                        sel = [sel]
                    db = self.env.get_db_cnx()
                    for name in sel:
                        mil = StructuredMilestone(self.env, name, db=db)
                        mil.delete(db=db)
                    db.commit()
                    req.redirect(req.href.admin(cat, page))

                # Set default milestone
                elif req.args.get('apply'):
                    if req.args.get('default'):
                        name = req.args.get('default')
                        self.config.set('ticket', 'default_milestone', name)
                        self.config.save()
                        req.redirect(req.href.admin(cat, page))

            data = {
                'view': 'list',
                'default': self.config.get('ticket', 'default_milestone'),
            }
            
        # Get ticket count
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        milestones = []
        structured_milestones = StructuredMilestone.select(self.env)
        mil_names = self._get_mil_names(structured_milestones)
        
        cursor.execute("SELECT milestone, COUNT(*) FROM ticket "
                   "WHERE milestone IN (%s) GROUP BY milestone" % ("%s,"*len(mil_names))[:-1], mil_names)
        mil_tkt_quantity = {}
        for mil, cnt in cursor:
            mil_tkt_quantity[mil]=cnt

        data.update({
            'date_hint': get_date_format_hint(),
            'milestones': [(mil, 0) for mil in structured_milestones],# we recover this anyway
            'structured_milestones': structured_milestones,
            'milestone_tickets_quantity': mil_tkt_quantity,
            'max_milestone_level': self.milestone_levels and len(self.milestone_levels)-1 or 0,
            'datetime_hint': get_datetime_format_hint()
        })
        return 'itteco_admin_milestones.html', data