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()
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)
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
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)
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
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)
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)
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()
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)
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
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])
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
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')
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()))
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
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)
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))
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'
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
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'
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'
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))
def create_milestone(self, name, description=None): milestone = Milestone(self.env) milestone.name = name if description is not None: milestone.description = description return milestone