Beispiel #1
0
class ImportProcessor(object):
    def __init__(self, env, req, filename, tickettime):
        self.env = env
        self.req = req
        self.filename = filename
        self.modified = {}
        self.added = {}

        # TODO: check that the tickets haven't changed since preview
        self.tickettime = tickettime

        # Keep the db to commit it all at once at the end
        self.db = self.env.get_db_cnx()
        self.missingemptyfields = None
        self.missingdefaultedfields = None
        self.computedfields = None
        self.importedfields = None

    def start(self, importedfields, reconciliate_by_owner_also, has_comments):
        # Index by row index, returns ticket id
        self.crossref = []
        self.lowercaseimportedfields = [f.lower() for f in importedfields]

    def process_missing_fields(self, missingfields, missingemptyfields,
                               missingdefaultedfields, computedfields):
        self.missingemptyfields = missingemptyfields
        self.missingdefaultedfields = missingdefaultedfields
        self.computedfields = computedfields

    def process_notimported_fields(self, notimportedfields):
        pass

    def process_comment_field(self, comment):
        pass

    def start_process_row(self, row_idx, ticket_id):
        from ticket import PatchedTicket
        if ticket_id > 0:
            # existing ticket
            self.ticket = PatchedTicket(self.env, tkt_id=ticket_id, db=self.db)

            # 'Ticket.time_changed' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            try:
                from trac.util.datefmt import to_timestamp
                time_changed = to_timestamp(self.ticket.time_changed)
            except ImportError:
                time_changed = int(self.ticket.time_changed)

            if time_changed > self.tickettime:
                # just in case, verify if it wouldn't be a ticket that has been modified in the future
                # (of course, it shouldn't happen... but who know). If it's the case, don't report it as an error
                if time_changed < int(time.time()):
                    # TODO: this is not working yet...
                    #
                    #raise TracError("Sorry, can not execute the import. "
                    #"The ticket #" + str(ticket_id) + " has been modified by someone else "
                    #"since preview. You must re-upload and preview your file to avoid overwriting the other changes.")
                    pass

        else:
            self.ticket = PatchedTicket(self.env, db=self.db)
        self.comment = ''

    def process_cell(self, column, cell):
        cell = unicode(cell)
        column = column.lower()
        # if status of new ticket is empty, force to use 'new'
        if not self.ticket.exists and column == 'status' and not cell:
            cell = 'new'
        # this will ensure that the changes are logged, see model.py Ticket.__setitem__
        self.ticket[column] = cell

    def process_comment(self, comment):
        self.comment = comment

    def _tickettime(self):
        try:
            # 'when' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            from trac.util.datefmt import to_datetime
            return to_datetime(self.tickettime)
        except ImportError:
            return self.tickettime

    def _save_ticket(self, ticket, with_comment=True):
        if with_comment:
            if self.comment:
                comment = "''Batch update from file " + self.filename + ":'' " + self.comment
            else:
                comment = "''Batch update from file " + self.filename + "''"
        else:
            comment = None
        ticket.save_changes(get_reporter_id(self.req),
                            comment,
                            when=self._tickettime(),
                            db=self.db)

    def end_process_row(self):

        if self.ticket.id == None:
            if self.missingemptyfields:
                for f in self.missingemptyfields:
                    if f in self.ticket.values and self.ticket[f] is None:
                        self.ticket[f] = ''

            if self.comment:
                self.ticket['description'] = self.ticket[
                    'description'] + "\n[[BR]][[BR]]\n''Batch insert from file " + self.filename + ":''\n" + self.comment

            if self.computedfields:
                for f in self.computedfields:
                    if f not in self.lowercaseimportedfields and \
                            self.computedfields[f] is not None and \
                            self.computedfields[f]['set']:
                        self.ticket[f] = self.computedfields[f]['value']

            self.ticket.insert(when=self._tickettime(), db=self.db)
            self.added[self.ticket.id] = 1
        else:
            if self.ticket.is_modified() or self.comment:
                self._save_ticket(self.ticket)
                self.modified[self.ticket.id] = 1

        self.crossref.append(self.ticket.id)
        self.ticket = None

    def process_new_lookups(self, newvalues):
        for field, names in newvalues.iteritems():
            if field == 'status':
                continue

            LOOKUPS = {
                'component': model.Component,
                'milestone': model.Milestone,
                'version': model.Version,
                'type': model.Type,
            }
            try:
                CurrentLookupEnum = LOOKUPS[field]
            except KeyError:

                class CurrentLookupEnum(model.AbstractEnum):
                    # here, you shouldn't put 'self.' before the class field.
                    type = field

            for name in names:
                lookup = CurrentLookupEnum(self.env, db=self.db)
                lookup.name = name
                lookup.insert()

    def process_new_users(self, newusers):
        pass

    # Rows is an array of dictionaries.
    # Each row is indexed by the field names in relativeticketfields.
    def process_relativeticket_fields(self, rows, relativeticketfields):
        from ticket import PatchedTicket

        # Find the WBS columns, if any.  We never expect to have more
        # than one but this is flexible and easy.  There's no good
        # reason to go to the trouble of ignoring extras.
        wbsfields = []
        for row in rows:
            for f in relativeticketfields:
                if row[f].find('.') != -1:
                    if f not in wbsfields:
                        wbsfields.append(f)

        # If WBS column present, build reverse lookup to find the
        # ticket ID from a WBS number.
        wbsref = {}
        if wbsfields != []:
            row_idx = 0
            for row in rows:
                wbsref[row[wbsfields[0]]] = self.crossref[row_idx]
                row_idx += 1

        row_idx = 0
        for row in rows:
            id = self.crossref[row_idx]

            # Get the ticket (added or updated in the main loop
            ticket = PatchedTicket(self.env, tkt_id=id, db=self.db)

            for f in relativeticketfields:
                # Get the value of the relative field column (e.g., "2,3")
                v = row[f]
                # If it's not empty, process the contents
                if len(v) > 0:
                    # Handle WBS numbers
                    if f in wbsfields:
                        if row[f].find('.') == -1:
                            # Top level, no parent
                            ticket[f] = ''
                        else:
                            # Get this task's wbs
                            wbs = row[f]
                            # Remove the last dot-delimited field
                            pwbs = wbs[:wbs.rindex(".")]
                            # Look up the parent's ticket ID
                            ticket[f] = str(wbsref[pwbs])
                    # Handle dependencies
                    else:
                        s = []
                        for r in v.split(","):
                            # Make the string value an integer
                            r = int(r)

                            # The relative ticket dependencies are 1-based,
                            # array indices are 0-based.  Convert and look up
                            # the new ticket ID of the other ticket.
                            i = self.crossref[r - 1]

                            # TODO check that i != id

                            s.append(str(i))

                        # Empty or not, use it to update the ticket
                        ticket[f] = ', '.join(s)

            self._save_ticket(ticket, with_comment=False)
            row_idx += 1

    def end_process(self, numrows):
        self.db.commit()

        data = {}
        data['title'] = 'Import completed'
        #data['report.title'] = data['title'].lower()
        notmodifiedcount = numrows - len(self.added) - len(self.modified)

        message = 'Successfully imported ' + str(numrows) + ' tickets (' + str(
            len(self.added)) + ' added, ' + str(len(
                self.modified)) + ' modified, ' + str(
                    notmodifiedcount) + ' unchanged).'

        data['message'] = Markup(
            "<style type=\"text/css\">#report-notfound { display:none; }</style>\n"
        ) + wiki_to_html(message, self.env, self.req)

        return 'import_preview.html', data, None
Beispiel #2
0
class ImportProcessor(object):
    def __init__(self, env, req, filename, tickettime):
        self.env = env
        self.req = req
        self.filename = filename
        self.modified = {}
        self.added = {}

        # TODO: check that the tickets haven't changed since preview
        self.tickettime = tickettime
        
        # Keep the db to commit it all at once at the end
        self.db = self.env.get_db_cnx()
        self.missingemptyfields = None
        self.missingdefaultedfields = None
        self.computedfields = None
        self.importedfields = None

    def start(self, importedfields, reconciliate_by_owner_also, has_comments):
        # Index by row index, returns ticket id
        self.crossref = []
        self.lowercaseimportedfields = [f.lower() for f in importedfields]

    def process_missing_fields(self, missingfields, missingemptyfields, missingdefaultedfields, computedfields):
        self.missingemptyfields = missingemptyfields
        self.missingdefaultedfields = missingdefaultedfields
        self.computedfields = computedfields

    def process_notimported_fields(self, notimportedfields):
        pass

    def process_comment_field(self, comment):
        pass

    def start_process_row(self, row_idx, ticket_id):
        from ticket import PatchedTicket
        if ticket_id > 0:
            # existing ticket
            self.ticket = PatchedTicket(self.env, tkt_id=ticket_id, db=self.db)

            # 'Ticket.time_changed' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            try:
                from trac.util.datefmt import to_timestamp
                time_changed = to_timestamp(self.ticket.time_changed)
            except ImportError:
                time_changed = int(self.ticket.time_changed)
                
            if time_changed > self.tickettime:
                # just in case, verify if it wouldn't be a ticket that has been modified in the future
                # (of course, it shouldn't happen... but who know). If it's the case, don't report it as an error
                if time_changed < int(time.time()):
                    # TODO: this is not working yet...
                    #
                    #raise TracError("Sorry, can not execute the import. "
                    #"The ticket #" + str(ticket_id) + " has been modified by someone else "
                    #"since preview. You must re-upload and preview your file to avoid overwriting the other changes.")
                    pass

        else:
            self.ticket = PatchedTicket(self.env, db=self.db)
        self.comment = ''

    def process_cell(self, column, cell):
        cell = unicode(cell)
        column = column.lower()
        # if status of new ticket is empty, force to use 'new'
        if not self.ticket.exists and column == 'status' and not cell:
            cell = 'new'
        # this will ensure that the changes are logged, see model.py Ticket.__setitem__
        self.ticket[column] = cell

    def process_comment(self, comment):
        self.comment = comment

    def _tickettime(self):
        try:
            # 'when' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            from trac.util.datefmt import to_datetime
            return to_datetime(self.tickettime)
        except ImportError:
            return self.tickettime


    def _save_ticket(self, ticket, with_comment=True):
        if with_comment:
            if self.comment:
                comment = "''Batch update from file " + self.filename + ":'' " + self.comment
            else:
                comment = "''Batch update from file " + self.filename + "''"
        else:
            comment=None
        ticket.save_changes(get_reporter_id(self.req), 
                            comment, 
                            when=self._tickettime(), 
                            db=self.db)

    def end_process_row(self):
                
        if self.ticket.id == None:
            if self.missingemptyfields:
                for f in self.missingemptyfields:
                    if f in self.ticket.values and self.ticket[f] is None:
                        self.ticket[f] = ''

            if self.comment:
                self.ticket['description'] = self.ticket['description'] + "\n[[BR]][[BR]]\n''Batch insert from file " + self.filename + ":''\n" + self.comment

            if self.computedfields:
                for f in self.computedfields:
                    if f not in self.lowercaseimportedfields and \
                            self.computedfields[f] is not None and \
                            self.computedfields[f]['set']:
                        self.ticket[f] = self.computedfields[f]['value']

            self.ticket.insert(when=self._tickettime(), db=self.db)
            self.added[self.ticket.id] = 1
        else:
            if self.ticket.is_modified() or self.comment:
                self._save_ticket(self.ticket)
                self.modified[self.ticket.id] = 1

        self.crossref.append(self.ticket.id)
        self.ticket = None

    def process_new_lookups(self, newvalues):
        for field, names in newvalues.iteritems():
            if field == 'status':
                continue
            
            LOOKUPS = {  'component': model.Component,
                         'milestone': model.Milestone,
                         'version':  model.Version,
                         'type': model.Type,
                         }
            try:
                CurrentLookupEnum = LOOKUPS[field]
            except KeyError:
                class CurrentLookupEnum(model.AbstractEnum):
                    # here, you shouldn't put 'self.' before the class field.
                    type = field

            for name in names:
                lookup = CurrentLookupEnum(self.env, db=self.db)
                lookup.name = name
                lookup.insert()

    def process_new_users(self, newusers):
        pass

    # Rows is an array of dictionaries.
    # Each row is indexed by the field names in relativeticketfields.
    def process_relativeticket_fields(self, rows, relativeticketfields):
        from ticket import PatchedTicket
        
        # Find the WBS columns, if any.  We never expect to have more
        # than one but this is flexible and easy.  There's no good
        # reason to go to the trouble of ignoring extras.
        wbsfields=[]
        for row in rows:
            for f in relativeticketfields:
                if row[f].find('.') != -1:
                    if f not in wbsfields:
                        wbsfields.append(f)


        # If WBS column present, build reverse lookup to find the
        # ticket ID from a WBS number.
        wbsref = {}
        if wbsfields != []:
            row_idx = 0
            for row in rows:
                wbsref[row[wbsfields[0]]] = self.crossref[row_idx]
                row_idx += 1

        row_idx = 0
        for row in rows:
            id = self.crossref[row_idx]

            # Get the ticket (added or updated in the main loop
            ticket = PatchedTicket(self.env, tkt_id=id, db=self.db)

            for f in relativeticketfields:
                # Get the value of the relative field column (e.g., "2,3")
                v = row[f]
                # If it's not empty, process the contents
                if len(v) > 0:
                    # Handle WBS numbers
                    if f in wbsfields:
                        if row[f].find('.') == -1:
                            # Top level, no parent
                            ticket[f] = ''
                        else:
                            # Get this task's wbs
                            wbs = row[f]
                            # Remove the last dot-delimited field
                            pwbs = wbs[:wbs.rindex(".")]
                            # Look up the parent's ticket ID
                            ticket[f] = str(wbsref[pwbs])
                    # Handle dependencies
                    else:
                        s = []
                        for r in v.split(","):
                            # Make the string value an integer
                            r = int(r)

                            # The relative ticket dependencies are 1-based,
                            # array indices are 0-based.  Convert and look up
                            # the new ticket ID of the other ticket.
                            i = self.crossref[r-1]

                            # TODO check that i != id

                            s.append(str(i))

                        # Empty or not, use it to update the ticket
                        ticket[f] = ', '.join(s)


            self._save_ticket(ticket, with_comment=False)
            row_idx += 1
        
            
    def end_process(self, numrows):
        self.db.commit()

        data = {}
        data['title'] = 'Import completed'
        #data['report.title'] = data['title'].lower()
        notmodifiedcount = numrows - len(self.added) - len(self.modified)

        message = 'Successfully imported ' + str(numrows) + ' tickets (' + str(len(self.added)) + ' added, ' + str(len(self.modified)) + ' modified, ' + str(notmodifiedcount) + ' unchanged).'

        data['message'] = Markup("<style type=\"text/css\">#report-notfound { display:none; }</style>\n") + wiki_to_html(message, self.env, self.req)

        return 'import_preview.html', data, None
Beispiel #3
0
class ImportProcessor(object):
    def __init__(self, env, req, filename, tickettime):
        self.env = env
        self.req = req
        self.filename = filename
        self.modifiedcount = 0
        self.notmodifiedcount = 0
        self.added = 0
        self.parent_tid = 0

        # TODO: check that the tickets haven't changed since preview
        self.tickettime = tickettime
        
        # Keep the db to commit it all at once at the end
        self.db = self.env.get_db_cnx()
        self.missingemptyfields = None
        self.missingdefaultedfields = None
        self.computedfields = None
        self.importedfields = None

    def start(self, importedfields, reconciliate_by_owner_also, has_comments):
        self.lowercaseimportedfields = [f.lower() for f in importedfields]

    def process_missing_fields(self, missingfields, missingemptyfields, missingdefaultedfields, computedfields):
        self.missingemptyfields = missingemptyfields
        self.missingdefaultedfields = missingdefaultedfields
        self.computedfields = computedfields

    def process_notimported_fields(self, notimportedfields):
        pass

    def process_comment_field(self, comment):
        pass

    def start_process_row(self, row_idx, ticket_id):
        from ticket import PatchedTicket
        if ticket_id > 0:
            # existing ticket
            self.ticket = PatchedTicket(self.env, tkt_id=ticket_id, db=self.db)

            # 'Ticket.time_changed' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            try:
                from trac.util.datefmt import to_timestamp
                time_changed = to_timestamp(self.ticket.time_changed)
            except ImportError:
                time_changed = int(self.ticket.time_changed)
                
            if time_changed > self.tickettime:
                # just in case, verify if it wouldn't be a ticket that has been modified in the future
                # (of course, it shouldn't happen... but who know). If it's the case, don't report it as an error
                if time_changed < int(time.time()):
                    # TODO: this is not working yet...
                    #
                    #raise TracError("Sorry, can not execute the import. "
                    #"The ticket #" + str(ticket_id) + " has been modified by someone else "
                    #"since preview. You must re-upload and preview your file to avoid overwriting the other changes.")
                    pass

        else:
            self.ticket = PatchedTicket(self.env, db=self.db)
        self.comment = ''

    def process_cell(self, column, cell):
        cell = unicode(cell)
        # this will ensure that the changes are logged, see model.py Ticket.__setitem__
        self.ticket[column.lower()] = cell

    def process_comment(self, comment):
        self.comment = comment

    def end_process_row(self, indent):
        try:
            # 'when' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            from trac.util.datefmt import to_datetime
            tickettime = to_datetime(self.tickettime)
        except ImportError:
            tickettime = self.tickettime
                
        if self.ticket.id == None:
            for f in self.missingemptyfields:
                if self.ticket.values.has_key(f) and self.ticket[f] == None:
                    self.ticket[f] = ''

            if self.comment:
                self.ticket['description'] = self.ticket['description'] + "\n[[BR]][[BR]]\n''Batch insert from file " + self.filename + ":''\n" + self.comment

            for f in self.computedfields:
                if f not in self.lowercaseimportedfields and self.computedfields[f] != None and self.computedfields[f]['set']:
                    self.ticket[f] = self.computedfields[f]['value']

            if (indent!=0) and (self.parent_tid!=0) and ('parents' in self.env.config['ticket-custom']):
                self.ticket['parents'] = str(self.parent_tid)

            self.added += 1
            self.ticket.insert(when=tickettime, db=self.db)
            if indent==0:
                 self.parent_tid = self.ticket.id

        else:
            if self.comment:
                message = "''Batch update from file " + self.filename + ":'' " + self.comment
            else:
                message = "''Batch update from file " + self.filename + "''"
            if self.ticket.is_modified() or self.comment:
                self.modifiedcount += 1
                self.ticket.save_changes(get_reporter_id(self.req), message, when=tickettime, db=self.db) # TODO: handle cnum, cnum = ticket.values['cnum'] + 1)
            else:
                self.notmodifiedcount += 1

        self.ticket = None

    def process_new_lookups(self, newvalues):
        for field, names in newvalues.iteritems():
            if field == 'status':
                continue
            
            if field == 'component':
                class CurrentLookupEnum(model.Component):
                    pass
            elif field == 'milestone':
                class CurrentLookupEnum(model.Milestone):
                    pass
            elif field == 'version':
                class CurrentLookupEnum(model.Version):
                    pass
            elif field == 'type':
                class CurrentLookupEnum(model.Type):
                    pass
            else:
                class CurrentLookupEnum(model.AbstractEnum):
                    # here, you shouldn't put 'self.' before the class field.
                    type = field

            for name in names:
                lookup = CurrentLookupEnum(self.env, db=self.db)
                lookup.name = name
                lookup.insert()

    def process_new_users(self, newusers):
        pass
            
    def end_process(self, numrows):
        self.db.commit()

        data = {}
        data['title'] = 'Import completed'
        #data['report.title'] = data['title'].lower()

        message = 'インポートに成功しました。 ' + str(numrows) + ' tickets (' + str(self.added) + ' 追加, ' + str(self.modifiedcount) + ' 更新, ' + str(self.notmodifiedcount) + ' 未更新).'

        data['message'] = Markup("<style type=\"text/css\">#report-notfound { display:none; }</style>\n") + wiki_to_html(message, self.env, self.req)

        return 'import_preview.html', data, None
Beispiel #4
0
class ImportProcessor(object):
    def __init__(self, env, req, filename, tickettime):
        self.env = env
        self.req = req
        self.filename = filename
        self.modifiedcount = 0
        self.notmodifiedcount = 0
        self.added = 0

        # TODO: check that the tickets haven't changed since preview
        self.tickettime = tickettime

        # Keep the db to commit it all at once at the end
        self.db = self.env.get_db_cnx()
        self.missingemptyfields = None
        self.missingdefaultedfields = None
        self.computedfields = None

    def start(self, importedfields, reconciliate_by_owner_also):
        pass

    def process_missing_fields(self, missingfields, missingemptyfields,
                               missingdefaultedfields, computedfields):
        self.missingemptyfields = missingemptyfields
        self.missingdefaultedfields = missingdefaultedfields
        self.computedfields = computedfields

    def process_notimported_fields(self, notimportedfields):
        pass

    def start_process_row(self, row_idx, ticket_id):
        from ticket import PatchedTicket
        if ticket_id > 0:
            # existing ticket
            self.ticket = PatchedTicket(self.env, tkt_id=ticket_id, db=self.db)

            # 'Ticket.time_changed' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            try:
                from trac.util.datefmt import to_timestamp
                time_changed = to_timestamp(self.ticket.time_changed)
            except ImportError:
                time_changed = int(self.ticket.time_changed)

            if time_changed > self.tickettime:
                # just in case, verify if it wouldn't be a ticket that has been modified in the future
                # (of course, it shouldn't happen... but who know). If it's the case, don't report it as an error
                if time_changed < int(time.time()):
                    # TODO: this is not working yet...
                    #
                    #raise TracError("Sorry, can not execute the import. "
                    #"The ticket #" + str(ticket_id) + " has been modified by someone else "
                    #"since preview. You must re-upload and preview your file to avoid overwriting the other changes.")
                    pass

        else:
            self.ticket = PatchedTicket(self.env, db=self.db)

    def process_cell(self, column, cell):
        cell = unicode(cell)
        # this will ensure that the changes are logged, see model.py Ticket.__setitem__
        self.ticket[column.lower()] = cell

    def end_process_row(self):
        try:
            # 'when' is a datetime in 0.11, and an int in 0.10.
            # if we have trac.util.datefmt.to_datetime, we're likely with 0.11
            from trac.util.datefmt import to_datetime
            tickettime = to_datetime(self.tickettime)
        except ImportError:
            tickettime = self.tickettime

        if self.ticket.id == None:
            for f in self.missingemptyfields:
                if self.ticket.values.has_key(f) and self.ticket[f] == None:
                    self.ticket[f] = ''
            for f in self.computedfields:
                if self.computedfields[f] != None and self.computedfields[f][
                        'set']:
                    self.ticket[f] = self.computedfields[f]['value']

            self.added += 1
            self.ticket.insert(when=tickettime, db=self.db)
        else:
            message = "Batch update from file " + self.filename
            if self.ticket.is_modified():
                self.modifiedcount += 1
                self.ticket.save_changes(
                    get_reporter_id(self.req),
                    message,
                    when=tickettime,
                    db=self.db
                )  # TODO: handle cnum, cnum = ticket.values['cnum'] + 1)
            else:
                self.notmodifiedcount += 1

        self.ticket = None

    def process_new_lookups(self, newvalues):
        for field, names in newvalues.iteritems():
            if names == []:
                continue
            if field == 'component':

                class CurrentLookupEnum(model.Component):
                    pass
            elif field == 'milestone':

                class CurrentLookupEnum(model.Milestone):
                    pass
            elif field == 'version':

                class CurrentLookupEnum(model.Version):
                    pass
            else:

                class CurrentLookupEnum(model.AbstractEnum):
                    # here, you shouldn't put 'self.' before the class field.
                    type = field

            for name in names:
                lookup = CurrentLookupEnum(self.env, db=self.db)
                lookup.name = name
                lookup.insert()

    def process_new_users(self, newusers):
        pass

    def end_process(self, numrows):
        self.db.commit()

        self.req.hdf['title'] = 'Import completed'
        self.req.hdf['report.title'] = self.req.hdf['title'].lower()

        message = 'Successfully imported ' + str(numrows) + ' tickets (' + str(
            self.added) + ' added, ' + str(
                self.modifiedcount) + ' modified, ' + str(
                    self.notmodifiedcount) + ' unchanged).'

        self.req.hdf['report.description'] = Markup(
            "<style type=\"text/css\">#report-notfound { display:none; }</style>\n"
        ) + wiki_to_html(message, self.env, self.req)

        self.req.hdf['report.numrows'] = 0
        self.req.hdf['report.mode'] = 'list'
        return 'report.cs', None