Пример #1
0
 def create_milestone(self, name, due=None, duration=20, db=None):
     """
     Creates a milestone with the given name and due
     date, the latter should be a datetime object
     """
     db, handle_ta = get_db_for_write(self.env, db)
     # Try to load the milestone first
     try:
         m = Milestone(self.env, name=name, db=db)
     except ResourceNotFound:
         # than we create it
         m = Milestone(self.env, db=db)
         m.name = name
         if due is not None and isinstance(due, datetime):
             dueo = due.toordinal() + duration
             m.due = mktime(datetime.fromordinal(dueo).timetuple())
         m.insert()
         if handle_ta:
             try:
                 db.commit()
                 # workaround for the fact that trac in 0.11.1 doesn't set exists correctly...
                 m._old_name = m.name
             except Exception, e:
                 self.env.log.warning(exception_to_unicode(e))
                 db.rollback()
Пример #2
0
    def process_request(self, req):
        milestone_id = req.args.get('id')
        req.perm('milestone', milestone_id).require('MILESTONE_VIEW')

        add_link(req, 'up', req.href.roadmap(), _('Roadmap'))

        action = req.args.get('action', 'view')
        try:
            milestone = Milestone(self.env, milestone_id)
        except ResourceNotFound:
            if 'MILESTONE_CREATE' not in req.perm('milestone', milestone_id):
                raise
            milestone = Milestone(self.env, None)
            milestone.name = milestone_id
            action = 'edit'  # rather than 'new' so that it works for POST/save

        if req.method == 'POST':
            if req.args.has_key('cancel'):
                if milestone.exists:
                    req.redirect(req.href.milestone(milestone.name))
                else:
                    req.redirect(req.href.roadmap())
            elif action == 'edit':
                return self._do_save(req, milestone)
            elif action == 'delete':
                self._do_delete(req, milestone)
        elif action in ('new', 'edit'):
            return self._render_editor(req, milestone)
        elif action == 'delete':
            return self._render_confirm(req, milestone)

        if not milestone.name:
            req.redirect(req.href.roadmap())

        return self._render_view(req, milestone)
Пример #3
0
    def process_request(self, req):
        milestone_id = req.args.get('id')

        req.perm.assert_permission('MILESTONE_VIEW')

        add_link(req, 'up', req.href.roadmap(), 'Roadmap')

        db = self.env.get_db_cnx()
        milestone = Milestone(self.env, milestone_id, db)
        action = req.args.get('action', 'view')

        if req.method == 'POST':
            if req.args.has_key('cancel'):
                if milestone.exists:
                    req.redirect(req.href.milestone(milestone.name))
                else:
                    req.redirect(req.href.roadmap())
            elif action == 'edit':
                self._do_save(req, db, milestone)
            elif action == 'delete':
                self._do_delete(req, db, milestone)
        elif action in ('new', 'edit'):
            self._render_editor(req, db, milestone)
        elif action == 'delete':
            self._render_confirm(req, db, milestone)
        else:
            self._render_view(req, db, milestone)

        if not milestone_id and action != 'new':
            req.redirect(req.href.roadmap())

        add_stylesheet(req, 'common/css/roadmap.css')
        return 'milestone.cs', None
Пример #4
0
    def test_milestone(self):
        milestone = Milestone(self.env)
        milestone.name = 'New target date'
        milestone.description = 'Lorem ipsum dolor sit amet'
        milestone.insert()
        so = self._get_so()
        self.assertEquals('%s:milestone:New target date' % self.basename,
                          so.doc_id)
        self.assertEquals('milestone', so.realm),
        self.assertEquals('New target date', so.id)
        self.assertTrue('New target date' in so.title)
        self.assertTrue('Lorem ipsum' in so.title)
        self.assertTrue('Lorem ipsum' in so.oneline)
        self.assertTrue('Lorem ipsum' in so.body)

        milestone.description = 'No latin filler here'
        milestone.due = datetime(2001, 01, 01, tzinfo=utc)
        milestone.update()
        so = self._get_so()
        self.assertEquals('%s:milestone:New target date' % self.basename,
                          so.doc_id)
        self.assertEquals('milestone', so.realm),
        self.assertEquals('New target date', so.id)
        self.assertEquals(milestone.due, so.changed)
        self.assertFalse('Lorem ipsum' in so.body)
        self.assertTrue('No latin filler here' in so.body)
Пример #5
0
 def change_milestone(self, name_to_change, name=None, description=None):
     milestone = Milestone(self.env, name_to_change)
     if name is not None:
         milestone.name = name
     if description is not None:
         milestone.description = description
     milestone.update()
     return milestone
Пример #6
0
 def test_can_save_due_date(self):
     # Added when Trac 0.12 was released as the format of the timestamp has changed in 0.12
     milestone = Milestone(self.env)
     milestone.name = 'fnord'
     milestone.insert()
     # in trac 0.11.1, milestone._old_name is not set to "fnord" at
     # insert() time, only on init() or update()
     # so we need to reload the object to be able to run update() on it
     milestone = Milestone(self.env, name='fnord')
     
     expected_time = now().replace(microsecond=0)
     milestone.due = expected_time
     milestone.completed = expected_time
     milestone.update()
     
     loaded_milestone = Milestone(self.env, name='fnord')
     self.assert_equals(expected_time, loaded_milestone.due)
     self.assert_equals(expected_time, loaded_milestone.completed)
Пример #7
0
 def testMilestoneRenamePropagatesToSprints(self):
     """Tests that the rename of a Milestone, propagates to the Sprints, this
     is an AgiloMilestone feature"""
     m = Milestone(self.env)
     m.name = 'test_me'
     m.insert()
     s = self.teh.create_sprint('my sprint', milestone=m.name)
     self.assert_equals(m.name, s.milestone)
     # AT: we need to reload the milestone as there is a problem in trac,
     # that the insert is not updating the _old_name, making the update
     # silently fail. I sent a patch for this
     m = Milestone(self.env, m.name)
     m.name = 'test_me_not'
     m.update()
     smm = SprintModelManager(self.env)
     smm.get_cache().invalidate()
     s = smm.get(name=s.name)
     self.assert_equals(m.name, s.milestone)
Пример #8
0
 def _create_milestone(self, name, duedate, description):
     m = Milestone(self.env)
     m.name = name
     m.description = description
     if duedate:
         if isinstance(duedate, type("")):
             m.due = parse_date(duedate)
         else:
             m.due = duedate
     m.insert()
Пример #9
0
 def test_can_index_delete(self):
     #arrange
     self.insert_milestone(self.DUMMY_MILESTONE_NAME)
     results = self.search_api.query("*")
     self.assertEqual(1, results.hits)
     #act
     Milestone(self.env, self.DUMMY_MILESTONE_NAME).delete()
     #assert
     results = self.search_api.query("*")
     self.print_result(results)
     self.assertEqual(0, results.hits)
Пример #10
0
    def process_request(self, req):
        req.perm.assert_permission('TICKET_CREATE')

        db = self.env.get_db_cnx()

        if req.method == 'POST' and not req.args.has_key('preview'):
            self._do_create(req, db)

        ticket = Ticket(self.env, db=db)
        ticket.populate(req.args)
        ticket.values.setdefault('reporter', util.get_reporter_id(req))

        if ticket.values.has_key('description'):
            description = wiki_to_html(ticket['description'], self.env, req, db)
            req.hdf['newticket.description_preview'] = description

        req.hdf['title'] = 'New Ticket'
        req.hdf['newticket'] = dict(zip(ticket.values.keys(),
                                        [util.escape(value) for value
                                         in ticket.values.values()]))

        field_names = [field['name'] for field in ticket.fields
                       if not field.get('custom')]
        if 'owner' in field_names:
            curr_idx = field_names.index('owner')
            if 'cc' in field_names:
                insert_idx = field_names.index('cc')
            else:
                insert_idx = len(field_names)
            if curr_idx < insert_idx:
                ticket.fields.insert(insert_idx, ticket.fields[curr_idx])
                del ticket.fields[curr_idx]

        for field in ticket.fields:
            name = field['name']
            del field['name']
            if name in ('summary', 'reporter', 'description', 'type', 'status',
                        'resolution'):
                field['skip'] = True
            elif name == 'owner':
                field['label'] = 'Assign to'
            elif name == 'milestone':
                # Don't make completed milestones available for selection
                options = field['options'][:]
                for option in field['options']:
                    milestone = Milestone(self.env, option, db=db)
                    if milestone.is_completed:
                        options.remove(option)
                field['options'] = [util.escape(option) for option in options]
            req.hdf['newticket.fields.' + name] = field

        add_stylesheet(req, 'common/css/ticket.css')
        return 'newticket.cs', None
Пример #11
0
 def testMilestoneRenamePropagatesToTickets(self):
     """Tests that the Milestone renaming is propagated to the tickets, this
     should work out of the box, as it is a Trac feature"""
     m = Milestone(self.env)
     m.name = 'test_me'
     m.insert()
     t = self.teh.create_ticket(Type.REQUIREMENT, {Key.MILESTONE: m.name})
     self.assert_equals(m.name, t[Key.MILESTONE])
     # AT: we need to reload the milestone as there is a problem in trac,
     # that the insert is not updating the _old_name, making the update
     # silently fail. I sent a patch for this
     m = Milestone(self.env, m.name)
     m.name = 'test_me_not'
     m.update()
     # test the changes happened in the DB
     db = self.env.get_db_cnx()
     cursor = db.cursor()
     cursor.execute("SELECT id, milestone FROM ticket WHERE milestone='test_me'")
     for row in cursor:
         self.fail("Found one old milestone in ticket: #%s (%s)" % \
                   (row[0], row[1]))
     t = self.teh.load_ticket(t)
     self.assert_equals(m.name, t[Key.MILESTONE])
Пример #12
0
    def _render_view(self, req, db, version):

        db = self.env.get_db_cnx()
        sql = "SELECT name FROM milestone " \
              "INNER JOIN milestone_version ON (name = milestone) " \
              "WHERE version = %s " \
              "ORDER BY due"
        cursor = db.cursor()
        cursor.execute(sql, (version.name,))

        milestones = []
        tickets = []
        milestone_stats = []

        for row in cursor:
            milestone = Milestone(self.env, row[0])
            milestones.append(milestone)

            mtickets = get_tickets_for_milestone(self.env, db, milestone.name,
                                                 'owner')
            mtickets = apply_ticket_permissions(self.env, req, mtickets)
            tickets += mtickets
            stat = get_ticket_stats(self.milestone_stats_provider, mtickets)
            milestone_stats.append(milestone_stats_data(self.env, req, stat, milestone.name))

        stats = get_ticket_stats(self.version_stats_provider, tickets)
        interval_hrefs = version_interval_hrefs(self.env, req, stats,
                                                [milestone.name for milestone in milestones])

        version.resource = Resource('version', version.name)
        context = Context.from_request(req, version.resource)

        version.is_released = version.time and version.time.date() < date.today()
        version.stats = stats
        version.interval_hrefs = interval_hrefs
        version.stats_href = [] # Not implemented yet, see th:#10349
        data = {
            'context': context,
            'version': version,
            'attachments': AttachmentModule(self.env).attachment_data(context),
            'milestones': milestones,
            'milestone_stats': milestone_stats,
            'show_milestone_description': self.show_milestone_description # Not implemented yet
        }

        add_stylesheet(req, 'extendedversion/css/version.css')
        add_script(req, 'common/js/folding.js')
        add_ctxtnav(req, _("Back to Versions"), req.href.versions())
        return 'version_view.html', data, None
Пример #13
0
 def _render_link(self, context, name, label, extra=''):
     try:
         milestone = Milestone(self.env, name)
     except TracError:
         milestone = None
     # Note: the above should really not be needed, `Milestone.exists`
     # should simply be false if the milestone doesn't exist in the db
     # (related to #4130)
     href = context.href.milestone(name)
     if milestone and milestone.exists:
         if 'MILESTONE_VIEW' in context.perm(milestone.resource):
             closed = 'closed ' if milestone.is_completed else ''
             return tag.a(label, class_='%smilestone' % closed,
                          href=href + extra)
     elif 'MILESTONE_CREATE' in context.perm('milestone', name):
         return tag.a(label, class_='missing milestone', href=href + extra,
                      rel='nofollow')
     return tag.a(label, class_='missing milestone')
Пример #14
0
 def test_remove_milestone(self):
     test_name = sys._getframe().f_code.co_name
     expected = self.expected_results[test_name]
     ticket = Ticket(self.env)
     ticket.populate({
         'reporter': 'santa',
         'summary': 'Summary line',
         'description': 'Lorem ipsum dolor sit amet',
     })
     ticket.insert()
     milestone = Milestone(self.env)
     milestone.name = 'New target date'
     milestone.description = 'Lorem ipsum dolor sit amet'
     milestone.insert()
     self.assertEqual(2, len(self._get_docs()))
     rv, output = self._execute('fulltext remove milestone')
     self.assertEqual(expected, output)
     self.assertEqual(1, len(self._get_docs()))
Пример #15
0
    def process_request(self, req):
        req.perm.assert_permission('TICKET_CREATE')

        db = self.env.get_db_cnx()

        if req.method == 'POST' and 'owner' in req.args and \
               not req.perm.has_permission('TICKET_MODIFY'):
            del req.args['owner']

        if req.method == 'POST' and not req.args.has_key('preview'):
            self._do_create(req, db)

        ticket = Ticket(self.env, db=db)
        ticket.populate(req.args)
        ticket.values['reporter'] = get_reporter_id(req, 'reporter')

        if ticket.values.has_key('description'):
            description = wiki_to_html(ticket['description'], self.env, req, db)
            req.hdf['newticket.description_preview'] = description

        req.hdf['title'] = 'New Ticket'
        req.hdf['newticket'] = ticket.values

        field_names = [field['name'] for field in ticket.fields
                       if not field.get('custom')]
        if 'owner' in field_names:
            curr_idx = field_names.index('owner')
            if 'cc' in field_names:
                insert_idx = field_names.index('cc')
            else:
                insert_idx = len(field_names)
            if curr_idx < insert_idx:
                ticket.fields.insert(insert_idx, ticket.fields[curr_idx])
                del ticket.fields[curr_idx]
        #处理newticket页面的表单
        for field in ticket.fields:
            name = field['name']
            del field['name']
            if name in ('summary', 'reporter', 'description', 'type', 'status',
                        'resolution'):
                field['skip'] = True
            elif name == 'owner':
                field['label'] = 'Assign to'
                if not req.perm.has_permission('TICKET_MODIFY'):
                    field['skip'] = True
            elif name == 'milestone':
                # Don't make completed milestones available for selection
                options = field['options'][:]
                for option in field['options']:
                    milestone = Milestone(self.env, option, db=db)
                    if milestone.is_completed:
                        options.remove(option)
                field['options'] = options
                #原来的field:newticket.fields
                #现在的field:newticket.fields.name.field
                # 下面是汉化:(不在上面完成,而是在这里统一加入代码
                #field['label']与field['name']都是可以的:
                #<?cs alt:field.label ?><?cs var:field.name ?>
            if name == 'priority':
                field['label'] = u'優先'
            elif name == 'owner':
                field['label'] = u'指派給'            
            elif name == 'keywords':
                field['label'] = u'關鍵字'
            elif name == 'version':
                field['label'] = u'版本'
            elif name == 'milestone':
                field['label'] = u'里程碑'
            elif name == 'component':
                field['label'] = u'组件'    
            elif name == 'cc':
                field['label'] = u'附件給'                
            req.hdf['newticket.fields.' + name] = field

        if req.perm.has_permission('TICKET_APPEND'):
            req.hdf['newticket.can_attach'] = True
            req.hdf['newticket.attachment'] = req.args.get('attachment')

        add_stylesheet(req, 'common/css/ticket.css')
        return 'newticket.cs', None
Пример #16
0
 def delete_milestone(self, name):
     """Deletes the given milestone"""
     conn = self.env.get_db_cnx()
     m = Milestone(self.env, name=name, db=conn)
     m.delete(db=conn)
Пример #17
0
 def testMilestoneIsPatched(self):
     """Tests that the Milestone is patched with AgiloMilestone"""
     m = Milestone(self.env)
     self.assert_true(isinstance(m, AgiloMilestone), \
                     "The milestone is: %s" % type(m))
Пример #18
0
    def _insert_ticket_data(self, req, db, ticket, reporter_id):
        """Insert ticket data into the hdf"""
        replyto = req.args.get('replyto')
        req.hdf['title'] = '#%d (%s)' % (ticket.id, ticket['summary'])
        req.hdf['ticket'] = ticket.values
        req.hdf['ticket'] = {
            'id': ticket.id,
            'href': req.href.ticket(ticket.id),
            'replyto': replyto
        }

        # -- Ticket fields

        for field in TicketSystem(self.env).get_ticket_fields():
            if field['type'] in ('radio', 'select'):
                value = ticket.values.get(field['name'])
                options = field['options']
                if field['name'] == 'milestone' \
                    and not req.perm.has_permission('TICKET_ADMIN'):
                    options = [
                        opt for opt in options
                        if not Milestone(self.env, opt, db=db).is_completed
                    ]
                if value and not value in options:
                    # Current ticket value must be visible even if its not in the
                    # possible values
                    options.append(value)
                field['options'] = options
            name = field['name']
            del field['name']
            if name in ('summary', 'reporter', 'description', 'type', 'status',
                        'resolution', 'owner'):
                field['skip'] = True
            req.hdf['ticket.fields.' + name] = field

        req.hdf['ticket.reporter_id'] = reporter_id
        req.hdf['ticket.description.formatted'] = wiki_to_html(
            ticket['description'], self.env, req, db)

        req.hdf['ticket.opened'] = format_datetime(ticket.time_created)
        req.hdf['ticket.opened_delta'] = pretty_timedelta(ticket.time_created)
        if ticket.time_changed != ticket.time_created:
            req.hdf['ticket'] = {
                'lastmod': format_datetime(ticket.time_changed),
                'lastmod_delta': pretty_timedelta(ticket.time_changed)
            }

        # -- Ticket Change History

        def quote_original(author, original, link):
            if not 'comment' in req.args:  # i.e. the comment was not yet edited
                req.hdf['ticket.comment'] = '\n'.join(
                    [u'En réponse à [%s %s]:' % (link, author)] +
                    [u'> %s' % line for line in original.splitlines()] + [''])

        if replyto == 'description':
            quote_original(ticket['reporter'], ticket['description'],
                           'ticket:%d' % ticket.id)
        replies = {}
        changes = []
        cnum = 0
        description_lastmod = description_author = None
        for change in self.grouped_changelog_entries(ticket, db):
            changes.append(change)
            # wikify comment
            comment = ''
            if 'comment' in change:
                comment = change['comment']
                change['comment'] = wiki_to_html(comment, self.env, req, db)
            if change['permanent']:
                cnum = change['cnum']
                # keep track of replies threading
                if 'replyto' in change:
                    replies.setdefault(change['replyto'], []).append(cnum)
                # eventually cite the replied to comment
                if replyto == str(cnum):
                    quote_original(change['author'], comment,
                                   'comment:%s' % replyto)
            if 'description' in change['fields']:
                change['fields']['description'] = ''
                description_lastmod = change['date']
                description_author = change['author']

        req.hdf['ticket'] = {
            'changes': changes,
            'replies': replies,
            'cnum': cnum + 1
        }
        if description_lastmod:
            req.hdf['ticket.description'] = {
                'lastmod': description_lastmod,
                'author': description_author
            }

        # -- Ticket Attachments

        req.hdf['ticket.attachments'] = attachments_to_hdf(
            self.env, req, db, 'ticket', ticket.id)
        if req.perm.has_permission('TICKET_APPEND'):
            req.hdf['ticket.attach_href'] = req.href.attachment(
                'ticket', ticket.id)

        # Add the possible actions to hdf
        actions = TicketSystem(self.env).get_available_actions(
            ticket, req.perm)
        for action in actions:
            req.hdf['ticket.actions.' + action] = '1'
Пример #19
0
    def process_request(self, req):
        req.perm.assert_permission('TICKET_CREATE')

        db = self.env.get_db_cnx()

        if req.method == 'POST' and 'owner' in req.args and \
               not req.perm.has_permission('TICKET_MODIFY'):
            del req.args['owner']

        if req.method == 'POST' and not req.args.has_key('preview'):
            self._do_create(req, db)

        ticket = Ticket(self.env, db=db)
        ticket.populate(req.args)
        ticket.values['reporter'] = get_reporter_id(req, 'reporter')

        if ticket.values.has_key('description'):
            description = wiki_to_html(ticket['description'], self.env, req,
                                       db)
            req.hdf['newticket.description_preview'] = description

        req.hdf['title'] = u'Nouveau ticket'
        req.hdf['newticket'] = ticket.values

        field_names = [
            field['name'] for field in ticket.fields if not field.get('custom')
        ]
        if 'owner' in field_names:
            curr_idx = field_names.index('owner')
            if 'cc' in field_names:
                insert_idx = field_names.index('cc')
            else:
                insert_idx = len(field_names)
            if curr_idx < insert_idx:
                ticket.fields.insert(insert_idx, ticket.fields[curr_idx])
                del ticket.fields[curr_idx]

        for field in ticket.fields:
            name = field['name']
            del field['name']
            if name in ('summary', 'reporter', 'description', 'type', 'status',
                        'resolution'):
                field['skip'] = True
            elif name == 'owner':
                field['label'] = u'Assigner à'
                if not req.perm.has_permission('TICKET_MODIFY'):
                    field['skip'] = True
            elif name == 'milestone':
                # Don't make completed milestones available for selection
                options = field['options'][:]
                for option in field['options']:
                    milestone = Milestone(self.env, option, db=db)
                    if milestone.is_completed:
                        options.remove(option)
                field['options'] = options
            field['label'] = translate(self.env, field['label'])
            req.hdf['newticket.fields.' + name] = field

        if req.perm.has_permission('TICKET_APPEND'):
            req.hdf['newticket.can_attach'] = True
            req.hdf['newticket.attachment'] = req.args.get('attachment')

        add_stylesheet(req, 'common/css/ticket.css')
        return 'newticket.cs', None
Пример #20
0
    def _insert_ticket_data(self, req, db, ticket, reporter_id):
        """Insert ticket data into the hdf"""
        replyto = req.args.get('replyto')
        req.hdf['title'] = '#%d (%s)' % (ticket.id, ticket['summary'])
        req.hdf['ticket'] = ticket.values
        req.hdf['ticket'] = {
            'id': ticket.id,
            'href': req.href.ticket(ticket.id),
            'replyto': replyto
            }

        # -- Ticket fields
        ZhField = {'Status': u'狀態', 'Description': u'詳述', 'Reporter': u'報告者', 'Cc': u'附件', 'Resolution': u'解決方法', 
                'Component': u'组件', 'summary': u'描述', 'Priority': u'優先程度', 'Keywords': u'關鍵字',
                 'Version': u'版本', 'Milestone': u'里程碑', 'Owner': u'負責人', 'Type': u'類型  '}   
        for field in TicketSystem(self.env).get_ticket_fields():
            if field['type'] in ('radio', 'select'):
                value = ticket.values.get(field['name'])
                options = field['options']
                if field['name'] == 'milestone' \
                    and not req.perm.has_permission('TICKET_ADMIN'):
                    options = [opt for opt in options if not
                               Milestone(self.env, opt, db=db).is_completed]
                if value and not value in options:
                    # Current ticket value must be visible even if its not in the
                    # possible values
                    options.append(value)
                field['options'] = options
            name = field['name']
            field['label'] = ZhField.get(field['label'],field['label'])
            del field['name']
            if name in ('summary', 'reporter', 'description', 'type', 'status',
                        'resolution', 'owner'):
                field['skip'] = True
            req.hdf['ticket.fields.' + name] = field

        req.hdf['ticket.reporter_id'] = reporter_id
        req.hdf['ticket.description.formatted'] = wiki_to_html(
            ticket['description'], self.env, req, db)

        req.hdf['ticket.opened'] = format_datetime(ticket.time_created)
        ZhUnit = {'second':u'秒','seconds':u'秒','minute':u'分鐘','minutes':u'分鐘','hour':u'小時','hours':u'小時',
                'day':u'天','days':u'天','week':u'週','weeks':u'週','year':u'年','years':u'年','month':u'月','months':u'月'}
                
        tempTime = pretty_timedelta(ticket.time_created)
        numAndUnit = tempTime.split(' ')
        numAndUnit[1] = ZhUnit.get(numAndUnit[1],numAndUnit[1])
        ZhCTime = ' '.join(numAndUnit)        
        
        req.hdf['ticket.opened_delta'] = ZhCTime
        
        tempTime = pretty_timedelta(ticket.time_changed)
        numAndUnit = tempTime.split(' ')
        numAndUnit[1] = ZhUnit.get(numAndUnit[1],numAndUnit[1])
        ZhATime = ' '.join(numAndUnit)
        if ticket.time_changed != ticket.time_created:
            req.hdf['ticket'] = {
                'lastmod': format_datetime(ticket.time_changed),
                'lastmod_delta': ZhATime
                }

        # -- Ticket Change History

        def quote_original(author, original, link):
            if not 'comment' in req.args: # i.e. the comment was not yet edited
                req.hdf['ticket.comment'] = '\n'.join(
                    ['Replying to [%s %s]:' % (link, author)] +
                    ['> %s' % line for line in original.splitlines()] + [''])

        if replyto == 'description':
            quote_original(ticket['reporter'], ticket['description'],
                           'ticket:%d' % ticket.id)
        replies = {}
        changes = []
        cnum = 0
        description_lastmod = description_author = None
        for change in self.grouped_changelog_entries(ticket, db):
            changes.append(change)
            # wikify comment
            comment = ''
            if 'comment' in change:
                comment = change['comment']
                change['comment'] = wiki_to_html(comment, self.env, req, db)
            if change['permanent']:
                cnum = change['cnum']
                # keep track of replies threading
                if 'replyto' in change:
                    replies.setdefault(change['replyto'], []).append(cnum)
                # eventually cite the replied to comment
                if replyto == str(cnum):
                    quote_original(change['author'], comment,
                                   'comment:%s' % replyto)
            if 'description' in change['fields']:
                change['fields']['description'] = ''
                description_lastmod = change['date']
                description_author = change['author']
        # 汉化"修改历史部分"
        tempList = []
        for comment_ in changes:
            newFields_ = {}
            for key, value in comment_['fields'].iteritems():
                newFields_.setdefault(ZhField.get(key.capitalize(),key),value)
            comment_['fields'] = newFields_
            tempList.append(comment_)
        changes = tempList
        req.hdf['ticket'] = {
            'changes': changes,
            'replies': replies,
            'cnum': cnum + 1
           }
        if description_lastmod:
            req.hdf['ticket.description'] = {'lastmod': description_lastmod,
                                             'author': description_author}

        # -- Ticket Attachments

        req.hdf['ticket.attachments'] = attachments_to_hdf(self.env, req, db,
                                                           'ticket', ticket.id)
        if req.perm.has_permission('TICKET_APPEND'):
            req.hdf['ticket.attach_href'] = req.href.attachment('ticket',
                                                                ticket.id)

        # Add the possible actions to hdf
        actions = TicketSystem(self.env).get_available_actions(ticket, req.perm)
        for action in actions:
            req.hdf['ticket.actions.' + action] = '1'
Пример #21
0
    def export_ical(self, req, query):
        """
        return the icalendar file
        """
        dtstart_key = self.config['icalendar'].get('dtstart','')
        duration_key = self.config['icalendar'].get('duration','')
        self.env.log.debug("dtstart_key=%s" % dtstart_key)
        self.env.log.debug("duration_key=%s" % duration_key)

        if dtstart_key != '':
            self.env.log.debug("use dtstart_key=%s" % dtstart_key)
            if dtstart_key not in query.cols:
                query.cols.append(dtstart_key)
        if duration_key != '':
            if duration_key not in query.cols:
                query.cols.append(duration_key)
        if 'priority' not in query.cols:
            query.cols.append('priority')
        if 'description' not in query.cols:
            query.cols.append('description')
        if 'changetime' not in query.cols:
            query.cols.append('changetime')
        if 'time' not in query.cols:
            query.cols.append('time')
        query.max = sys.maxint
        results = query.execute(req)
        cols = query.get_columns()
        content = StringIO()
        content.write('BEGIN:VCALENDAR\r\n')
        content.write('VERSION:2.0\r\n')
        content.write('PRODID:2.0:-//Edgewall Software//NONSGML Trac 0.11//EN\r\n')
        content.write('METHOD:PUBLISH\r\n')
        content.write('X-WR-CALNAME: test\r\n')

        attr_map = {
                    "summary" : "SUMMARY",
                    "type" :  "CATEGORIES",
                    "description" : "DESCRIPTION"
                   }
        priority_map = {
                    'blocker' :  1,
                    'critical' :  2,
                    'major' : 6,
                    'minor' : 8,
                    'trivial' : 9
                    }

        custom_priority_map = self.config['icalendar'].get('priority_map',None)
        if custom_priority_map != None:
            for m in custom_priority_map.split(","):
                k = m.split(":")
                if len(k) == 2:
                    priority_map[k[0]] = int(k[1])

        def write_prop(name, value, params={}):
            propname = ';'.join([name] + [k + '=' + v for k, v in params.items()])
            propvalue = value.replace('\n','\n ').replace('\r\n \r\n','\r\n')
            content.write("%s:%s\r\n" % (propname,propvalue))
        for result in results:
            ticket = Resource('ticket', result['id'])
            if 'TICKET_VIEW' in req.perm(ticket):
                kind = "VEVENT"
                dtstart = None
                if dtstart_key != '':
                    dtstart = self.parse_date(result[dtstart_key])
                due = None
                if dtstart == None :
                    kind = "VTODO"
                    self.env.log.debug("is TODO")
                    if result.has_key("milestone"):
                        milestone_key = result["milestone"]
                        if milestone_key != "--" and milestone_key != "":
                            self.env.log.debug("Milestone !" + milestone_key)
                            milestone = Milestone(self.env,milestone_key)
                            due = milestone.due
                                
                content.write("BEGIN:%s\r\n" % kind)
                content.write("UID:<%s@%s>\r\n" % (get_resource_url(self.env,ticket,req.href),os.getenv('SERVER_NAME')))
                if dtstart != None:
                    self.format_date(content,"DTSTART",dtstart)
                    if duration_key != '':
                        duration = self.parse_duration(result[duration_key])
                        if type(duration) == datetime.timedelta :
                            content.write("DURATION:P%dDT%dS\r\n" % (duration.days, duration.seconds))
                        else :
                            content.write("DURATION:%s\r\n" % duration)
                elif due != None:
                    self.format_date(content,"DUE",due,False)
                self.format_date(content,"CREATED",result["time"])
                self.format_date(content,"DTSTAMP",result["changetime"])
                protocol = "http"
                if os.getenv('SERVER_PROTOCOL') != None :
                    if "HTTPS" in os.getenv('SERVER_PROTOCOL') :
                        protocol = "https"
                content.write("URL:%s://%s%s\r\n" % (protocol,os.getenv('SERVER_NAME'),get_resource_url(self.env,ticket,req.href)))
                priority = None
                try:
                    priority = priority_map[result['priority']]
                except:
                    self.env.log.debug("unmapped priority %s" % result['priority'])
                if priority != None:
                    content.write("PRIORITY;VALUE=%s:%d\r\n" % (result['priority'],priority))

                for key in attr_map:
                   if key in cols:
                       write_prop(attr_map[key], unicode(result[key]).encode('utf-8'),{})
                content.write("END:%s\r\n" % kind)
        content.write('END:VCALENDAR\r\n')
        return content.getvalue(), 'text/calendar;charset=utf-8'
Пример #22
0
    def _do_save(self, req, milestone):
        if milestone.exists:
            req.perm(milestone.resource).require('MILESTONE_MODIFY')
        else:
            req.perm(milestone.resource).require('MILESTONE_CREATE')

        old_name = milestone.name
        new_name = req.args.get('name')

        milestone.description = req.args.get('description', '')

        if 'due' in req.args:
            due = req.args.get('duedate', '')
            milestone.due = user_time(req, parse_date, due, hint='datetime') \
                            if due else None
        else:
            milestone.due = None

        completed = req.args.get('completeddate', '')
        retarget_to = req.args.get('target')

        # Instead of raising one single error, check all the constraints and
        # let the user fix them by going back to edit mode showing the warnings
        warnings = []

        def warn(msg):
            add_warning(req, msg)
            warnings.append(msg)

        # -- check the name
        # If the name has changed, check that the milestone doesn't already
        # exist
        # FIXME: the whole .exists business needs to be clarified
        #        (#4130) and should behave like a WikiPage does in
        #        this respect.
        try:
            new_milestone = Milestone(self.env, new_name)
            if new_milestone.name == old_name:
                pass  # Creation or no name change
            elif new_milestone.name:
                warn(
                    _(
                        'Milestone "%(name)s" already exists, please '
                        'choose another name.',
                        name=new_milestone.name))
            else:
                warn(_('You must provide a name for the milestone.'))
        except ResourceNotFound:
            milestone.name = new_name

        # -- check completed date
        if 'completed' in req.args:
            completed = user_time(req, parse_date, completed,
                                  hint='datetime') if completed else None
            if completed and completed > datetime.now(utc):
                warn(_('Completion date may not be in the future'))
        else:
            completed = None
        milestone.completed = completed

        if warnings:
            return self._render_editor(req, milestone)

        # -- actually save changes
        if milestone.exists:
            milestone.update()
            # eventually retarget opened tickets associated with the milestone
            if 'retarget' in req.args and completed:
                self.env.db_transaction(
                    """
                    UPDATE ticket SET milestone=%s
                    WHERE milestone=%s and status != 'closed'
                    """, (retarget_to, old_name))
                self.log.info("Tickets associated with milestone %s "
                              "retargeted to %s" % (old_name, retarget_to))
        else:
            milestone.insert()

        add_notice(req, _("Your changes have been saved."))
        req.redirect(req.href.milestone(milestone.name))
Пример #23
0
 def create_milestone(self, name, description=None):
     milestone = Milestone(self.env)
     milestone.name = name
     if description is not None:
         milestone.description = description
     return milestone