Index: /main/waeup.kofa/trunk/src/waeup/kofa/utils/browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/utils/browser.py	(revision 9126)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/utils/browser.py	(revision 9127)
@@ -42,4 +42,28 @@
     return
 
+def removeStudentMessage(student_id, number):
+    students = grok.getSite()['students']
+    student = students.get(student_id, None)
+    if student:
+        history = IObjectHistory(student)
+        success, text = history.removeMessage(number)
+    return success, text
+
+def removeApplicantMessage(applicant_id, number):
+    applicants = grok.getSite()['applicants']
+    try:
+        container, application_number = applicant_id.split('_')
+    except:
+        return False, 'applicant_id is wrong'
+    container = applicants.get(container, None)
+    if not container:
+        return False, 'No such container'
+    applicant = container.get(application_number, None)
+    if applicant is None:
+        return False, 'No such applicant'
+    history = IObjectHistory(applicant)
+    success, text = history.removeMessage(number)
+    return success, text
+
 class ReindexPage(UtilityView, grok.View):
     """ Reindex view.
@@ -94,4 +118,34 @@
         return
 
+class RemoveStudentHistoryMessage(UtilityView, grok.View):
+    """ View to remove a single student history entry.
+
+    """
+    grok.context(IUniversity)
+    grok.name('remove_student_history_message')
+    grok.require('waeup.managePortal')
+
+    def update(self,student_id=None, number=None):
+        if None in (student_id, number):
+            self.flash('Syntax: /remove_student_history_message?student_id=[id]&number=[line number, starting with 0]')
+            return
+        try:
+            number=int(number)
+        except:
+            self.flash('Error')
+            return
+        success, text = removeStudentMessage(student_id, number)
+        if not success:
+            self.flash('Error: %s' % text)
+            return
+        self.context.logger.info(
+            "line '%s' removed in %s history" % (text, student_id))
+        self.flash('Finished')
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
+
 class ModifyAllApplicantHistory(UtilityView, grok.View):
     """ View to modify all student histories.
@@ -115,2 +169,32 @@
         self.redirect(self.url(self.context, '@@index'))
         return
+
+class RemoveApplicantHistoryMessage(UtilityView, grok.View):
+    """ View to remove a single applicant history entry.
+
+    """
+    grok.context(IUniversity)
+    grok.name('remove_applicant_history_message')
+    grok.require('waeup.managePortal')
+
+    def update(self,applicant_id=None, number=None):
+        if None in (applicant_id, number):
+            self.flash('Syntax: /remove_applicant_history_message?applicant_id=[id]&number=[line number, starting with 0]')
+            return
+        try:
+            number=int(number)
+        except:
+            self.flash('Error')
+            return
+        success, text = removeApplicantMessage(applicant_id, number)
+        if not success:
+            self.flash('Error: %s' % text)
+            return
+        self.context.logger.info(
+            "line '%s' removed in %s history" % (text, applicant_id))
+        self.flash('Finished')
+        return
+
+    def render(self):
+        self.redirect(self.url(self.context, '@@index'))
+        return
Index: /main/waeup.kofa/trunk/src/waeup/kofa/utils/tests/test_browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/utils/tests/test_browser.py	(revision 9126)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/utils/tests/test_browser.py	(revision 9127)
@@ -62,4 +62,25 @@
             self.student.history.messages[0])
 
+    def test_remove_student_history_message(self):
+        self.assertTrue('Record created by system' in
+            self.student.history.messages[0])
+        self.assertEqual(len(self.student.history.messages),1)
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open('http://localhost/app/remove_student_history_message')
+        self.assertTrue(
+            'Syntax: /remove_student_history_message?student_id=[id]&number=[line number, starting with 0]'
+            in self.browser.contents)
+        self.browser.open(
+            'http://localhost/app/remove_student_history_message?student_id=%s&number=0' % self.student.student_id)
+        self.assertTrue('Finished' in self.browser.contents)
+        self.assertEqual(len(self.student.history.messages),0)
+        logfile = os.path.join(
+            self.app['datacenter'].storage, 'logs', 'main.log')
+        logcontent = open(logfile).read()
+        self.assertMatches(
+            "...zope.mgr - line '<YYYY-MM-DD hh:mm:ss> UTC - "
+            "Record created by system' removed in K1000000 history",
+            logcontent)
+
     def test_reindex(self):
         self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
@@ -96,2 +117,23 @@
         self.assertTrue('Application initialized by me' in
             self.applicant.history.messages[0])
+
+    def test_remove_applicant_history_message(self):
+        self.assertTrue('Application initialized by system' in
+            self.applicant.history.messages[0])
+        self.assertEqual(len(self.applicant.history.messages),1)
+        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+        self.browser.open('http://localhost/app/remove_applicant_history_message')
+        self.assertTrue(
+            'Syntax: /remove_applicant_history_message?applicant_id=[id]&number=[line number, starting with 0]'
+            in self.browser.contents)
+        self.browser.open(
+            'http://localhost/app/remove_applicant_history_message?applicant_id=%s&number=0' % self.applicant.applicant_id)
+        self.assertTrue('Finished' in self.browser.contents)
+        self.assertEqual(len(self.applicant.history.messages),0)
+        logfile = os.path.join(
+            self.app['datacenter'].storage, 'logs', 'main.log')
+        logcontent = open(logfile).read()
+        self.assertMatches(
+            "...zope.mgr - line '<YYYY-MM-DD hh:mm:ss> UTC - "
+            "Application initialized by system' removed in %s history"
+            % self.applicant.applicant_id, logcontent)
