changeset 3904:91008ec8f9a0

retire "topic" usage "Topic" still appears in the locale files. I'm sure we need to support that for existing trackers. I *think* they don't care about any of the other changes that have been made. I also left Ka-Ping Yee's original design document unchanged. This takes care of sf feature request [SF#953161]
author Justus Pendleton <jpend@users.sourceforge.net>
date Sun, 16 Sep 2007 02:45:11 +0000
parents a90fa2e08a0a
children 6733a7cce7f4
files doc/customizing.txt doc/design.txt doc/overview.txt doc/user_guide.txt roundup/roundupdb.py scripts/import_sf.py templates/classic/html/help_controls.js templates/classic/html/issue.index.html templates/classic/html/issue.item.html templates/classic/html/issue.search.html templates/classic/schema.py templates/minimal/html/help_controls.js test/test_cgi.py
diffstat 13 files changed, 97 insertions(+), 98 deletions(-) [+]
line wrap: on
line diff
--- a/doc/customizing.txt	Fri Sep 14 15:55:25 2007 +0000
+++ b/doc/customizing.txt	Sun Sep 16 02:45:11 2007 +0000
@@ -2,7 +2,7 @@
 Customising Roundup
 ===================
 
-:Version: $Revision: 1.220 $
+:Version: $Revision: 1.221 $
 
 .. This document borrows from the ZopeBook section on ZPT. The original is at:
    http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
@@ -445,7 +445,7 @@
 
     file = FileClass(db, "file", name=String())
 
-    issue = IssueClass(db, "issue", topic=Multilink("keyword"),
+    issue = IssueClass(db, "issue", keyword=Multilink("keyword"),
         status=Link("status"), assignedto=Link("user"),
         priority=Link("priority"))
     issue.setkey('title')
@@ -2481,10 +2481,10 @@
 been added for clarity)::
 
     /issue?status=unread,in-progress,resolved&
-        topic=security,ui&
+        keyword=security,ui&
         @group=priority,-status&
         @sort=-activity&
-        @filters=status,topic&
+        @filters=status,keyword&
         @columns=title,status,fixer
 
 The index view is determined by two parts of the specifier: the layout
@@ -2503,11 +2503,11 @@
 
 The example specifies an index of "issue" items. Only items with a
 "status" of either "unread" or "in-progress" or "resolved" are
-displayed, and only items with "topic" values including both "security"
+displayed, and only items with "keyword" values including both "security"
 and "ui" are displayed. The items are grouped by priority arranged in
 ascending order and in descending order by status; and within
 groups, sorted by activity, arranged in descending order. The filter
-section shows filters for the "status" and "topic" properties, and the
+section shows filters for the "status" and "keyword" properties, and the
 table includes columns for the "title", "status", and "fixer"
 properties.
 
@@ -2904,7 +2904,7 @@
 1. Modify the ``schema.py``::
 
     issue = IssueClass(db, "issue", 
-                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    assignedto=Link("user"), keyword=Multilink("keyword"),
                     priority=Link("priority"), status=Link("status"),
                     due_date=Date())
 
@@ -3398,7 +3398,7 @@
    ``schema.py``)::
 
     issue = IssueClass(db, "issue", 
-                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    assignedto=Link("user"), keyword=Multilink("keyword"),
                     priority=Link("priority"), status=Link("status"),
                     times=Multilink("timelog"))
 
@@ -3571,7 +3571,7 @@
 
     # store issues related to those systems
     support = IssueClass(db, "support", 
-                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    assignedto=Link("user"), keyword=Multilink("keyword"),
                     status=Link("status"), deadline=Date(),
                     affects=Multilink("system"))
 
@@ -4055,14 +4055,14 @@
    this class in your tracker's ``schema.py`` file. Change this::
 
     issue = IssueClass(db, "issue", 
-                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    assignedto=Link("user"), keyword=Multilink("keyword"),
                     priority=Link("priority"), status=Link("status"))
 
    to this, adding the blockers entry::
 
     issue = IssueClass(db, "issue", 
                     blockers=Multilink("issue"),
-                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    assignedto=Link("user"), keyword=Multilink("keyword"),
                     priority=Link("priority"), status=Link("status"))
 
 2. Add the new ``blockers`` property to the ``issue.item.html`` edit
@@ -4204,33 +4204,32 @@
 history at the bottom of the issue page - look for a "link" event to
 another issue's "blockers" property.
 
-Add users to the nosy list based on the topic
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Add users to the nosy list based on the keyword
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Let's say we need the ability to automatically add users to the nosy
 list based
-on the occurance of a topic. Every user should be allowed to edit their
-own list of topics for which they want to be added to the nosy list.
+on the occurance of a keyword. Every user should be allowed to edit their
+own list of keywords for which they want to be added to the nosy list.
 
 Below, we'll show that this change can be done with minimal
 understanding of the Roundup system, using only copy and paste.
 
 This requires three changes to the tracker: a change in the database to
-allow per-user recording of the lists of topics for which he wants to
+allow per-user recording of the lists of keywords for which he wants to
 be put on the nosy list, a change in the user view allowing them to edit
-this list of topics, and addition of an auditor which updates the nosy
-list when a topic is set.
-
-Adding the nosy topic list
-::::::::::::::::::::::::::
-
-The change to make in the database, is that for any user there should be
-a list of topics for which he wants to be put on the nosy list. Adding
-a ``Multilink`` of ``keyword`` seems to fullfill this (note that within
-the code, topics are called ``keywords``.) As such, all that has to be
-done is to add a new field to the definition of ``user`` within the
-file ``schema.py``.  We will call this new field ``nosy_keywords``, and
-the updated definition of user will be::
+this list of keywords, and addition of an auditor which updates the nosy
+list when a keyword is set.
+
+Adding the nosy keyword list
+::::::::::::::::::::::::::::
+
+The change to make in the database, is that for any user there should be a list
+of keywords for which he wants to be put on the nosy list. Adding a
+``Multilink`` of ``keyword`` seems to fullfill this. As such, all that has to
+be done is to add a new field to the definition of ``user`` within the file
+``schema.py``.  We will call this new field ``nosy_keywords``, and the updated
+definition of user will be::
 
     user = Class(db, "user", 
                     username=String(),   password=Password(),
@@ -4241,22 +4240,22 @@
                     timezone=String(),
                     nosy_keywords=Multilink('keyword'))
  
-Changing the user view to allow changing the nosy topic list
-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-We want any user to be able to change the list of topics for which
+Changing the user view to allow changing the nosy keyword list
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+We want any user to be able to change the list of keywords for which
 he will by default be added to the nosy list. We choose to add this
 to the user view, as is generated by the file ``html/user.item.html``.
 We can easily 
-see that the topic field in the issue view has very similar editing
-requirements as our nosy topics, both being lists of topics. As
-such, we look for Topics in ``issue.item.html``, and extract the
+see that the keyword field in the issue view has very similar editing
+requirements as our nosy keywords, both being lists of keywords. As
+such, we look for Keywords in ``issue.item.html``, and extract the
 associated parts from there. We add this to ``user.item.html`` at the 
 bottom of the list of viewed items (i.e. just below the 'Alternate
 E-mail addresses' in the classic template)::
 
  <tr>
-  <th>Nosy Topics</th>
+  <th>Nosy Keywords</th>
   <td>
   <span tal:replace="structure context/nosy_keywords/field" />
   <span tal:replace="structure python:db.keyword.classhelp(property='nosy_keywords')" />
@@ -4269,7 +4268,7 @@
 
 The more difficult part is the logic to add
 the users to the nosy list when required. 
-We choose to perform this action whenever the topics on an
+We choose to perform this action whenever the keywords on an
 item are set (this includes the creation of items).
 Here we choose to start out with a copy of the 
 ``detectors/nosyreaction.py`` detector, which we copy to the file
@@ -4290,8 +4289,8 @@
 code, which handled adding the assignedto user(s) to the nosy list in
 ``updatenosy``, should be replaced by a block of code to add the
 interested users to the nosy list. We choose here to loop over all
-new topics, than looping over all users,
-and assign the user to the nosy list when the topic occurs in the user's
+new keywords, than looping over all users,
+and assign the user to the nosy list when the keyword occurs in the user's
 ``nosy_keywords``. The next part in ``updatenosy`` -- adding the author
 and/or recipients of a message to the nosy list -- is obviously not
 relevant here and is thus deleted from the new auditor. The last
@@ -4299,7 +4298,7 @@
 This results in the following function::
 
     def update_kw_nosy(db, cl, nodeid, newvalues):
-        '''Update the nosy list for changes to the topics
+        '''Update the nosy list for changes to the keywords
         '''
         # nodeid will be None if this is a new node
         current = {}
@@ -4324,17 +4323,17 @@
                 if not current.has_key(value):
                     current[value] = 1
 
-        # add users with topic in nosy_keywords to the nosy list
-        if newvalues.has_key('topic') and newvalues['topic'] is not None:
-            topic_ids = newvalues['topic']
-            for topic in topic_ids:
+        # add users with keyword in nosy_keywords to the nosy list
+        if newvalues.has_key('keyword') and newvalues['keyword'] is not None:
+            keyword_ids = newvalues['keyword']
+            for keyword in keyword_ids:
                 # loop over all users,
-                # and assign user to nosy when topic in nosy_keywords
+                # and assign user to nosy when keyword in nosy_keywords
                 for user_id in db.user.list():
                     nosy_kw = db.user.get(user_id, "nosy_keywords")
                     found = 0
                     for kw in nosy_kw:
-                        if kw == topic:
+                        if kw == keyword:
                             found = 1
                     if found:
                         current[user_id] = 1
@@ -4354,10 +4353,10 @@
 Multiple additions
     When a user, after automatic selection, is manually removed
     from the nosy list, he is added to the nosy list again when the
-    topic list of the issue is updated. A better design might be
-    to only check which topics are new compared to the old list
-    of topics, and only add users when they have indicated
-    interest on a new topic.
+    keyword list of the issue is updated. A better design might be
+    to only check which keywords are new compared to the old list
+    of keywords, and only add users when they have indicated
+    interest on a new keyword.
 
     The code could also be changed to only trigger on the ``create()``
     event, rather than also on the ``set()`` event, thus only setting
@@ -4367,8 +4366,8 @@
     In the auditor, there is a loop over all users. For a site with
     only few users this will pose no serious problem; however, with
     many users this will be a serious performance bottleneck.
-    A way out would be to link from the topics to the users who
-    selected these topics as nosy topics. This will eliminate the
+    A way out would be to link from the keywords to the users who
+    selected these keywords as nosy keywords. This will eliminate the
     loop over all users.
 
 Changes to Security and Permissions
--- a/doc/design.txt	Fri Sep 14 15:55:25 2007 +0000
+++ b/doc/design.txt	Sun Sep 16 02:45:11 2007 +0000
@@ -819,7 +819,7 @@
     Class(db, "keyword", name=hyperdb.String())
 
     Class(db, "issue", fixer=hyperdb.Multilink("user"),
-                       topic=hyperdb.Multilink("keyword"),
+                       keyword=hyperdb.Multilink("keyword"),
                        priority=hyperdb.Link("priority"),
                        status=hyperdb.Link("status"))
 
@@ -1250,10 +1250,10 @@
 clarity)::
 
     /issue?status=unread,in-progress,resolved&
-        topic=security,ui&
+        keyword=security,ui&
         :group=priority,-status&
         :sort=-activity&
-        :filters=status,topic&
+        :filters=status,keyword&
         :columns=title,status,fixer
 
 
@@ -1274,11 +1274,11 @@
 
 The example specifies an index of "issue" items. Only issues with a
 "status" of either "unread" or "in-progres" or "resolved" are displayed,
-and only issues with "topic" values including both "security" and "ui"
+and only issues with "keyword" values including both "security" and "ui"
 are displayed.  The items are grouped by priority arranged in ascending
 order and in descending order by status; and within groups, sorted by
 activity, arranged in descending order. The filter section shows
-filters for the "status" and "topic" properties, and the table includes
+filters for the "status" and "keyword" properties, and the table includes
 columns for the "title", "status", and "fixer" properties.
 
 Associated with each issue class is a default layout specifier.  The
--- a/doc/overview.txt	Fri Sep 14 15:55:25 2007 +0000
+++ b/doc/overview.txt	Sun Sep 16 02:45:11 2007 +0000
@@ -147,7 +147,7 @@
 only sometimes fall into one category; often,
 a piece of information may be related to several concepts.
 
-For example, forcing each item into a single topic
+For example, forcing each item into a single keyword
 category is not just suboptimal but counterproductive:
 seekers of that
 item may expect to find it in a different category
@@ -245,7 +245,7 @@
 The *multilink* type is for a list of links to any
 number of other items in the in the database.  A *multilink*
 property, for example, can be used to refer to related items
-or topic categories relevant to an item.
+or keyword categories relevant to an item.
 
 For Roundup, all items have four properties that are not customizable:
 
@@ -314,13 +314,13 @@
     #   superseder = Multilink("issue")
     #   (it also gets the Class properties creation, activity and creator)
     issue = IssueClass(db, "issue", 
-                    assignedto=Link("user"), topic=Multilink("keyword"),
+                    assignedto=Link("user"), keyword=Multilink("keyword"),
                     priority=Link("priority"), status=Link("status"))
 
 The **assignedto** property assigns
 responsibility for an item to a person or a list of people.
-The **topic** property places the
-item in an arbitrary number of relevant topic sets (see
+The **keyword** property places the
+item in an arbitrary number of relevant keyword sets (see
 the section on `Browsing and Searching`_).
 
 The **prority** and **status** values are initially:
@@ -449,11 +449,11 @@
 messages they might have missed.
 
 We can take this a step further and
-permit users to monitor particular topics or classifications of items
+permit users to monitor particular keywords or classifications of items
 by allowing other kinds of items to also have their own nosy lists.
 For example, a manager could be on the
 nosy list of the priority value item for "critical", or a
-developer could be on the nosy list of the topic value item for "security".
+developer could be on the nosy list of the keyword value item for "security".
 The recipients are then determined by the union of the nosy lists on the
 item and all the items it links to.
 
@@ -552,7 +552,7 @@
   (the filter selects the *intersection* of the sets of items
   associated with the active options)
 
-For a *multilink* property like **topic**,
+For a *multilink* property like **keyword**,
 one possibility is to show, as hyperlinks, the keywords whose
 sets have non-empty intersections with the currently displayed set of
 items.  Sorting the keywords by popularity seems
--- a/doc/user_guide.txt	Fri Sep 14 15:55:25 2007 +0000
+++ b/doc/user_guide.txt	Sun Sep 16 02:45:11 2007 +0000
@@ -2,7 +2,7 @@
 User Guide
 ==========
 
-:Version: $Revision: 1.36 $
+:Version: $Revision: 1.37 $
 
 .. contents::
 
@@ -112,7 +112,7 @@
 Constrained (link and multilink) properties
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Fields like "Assigned To" and "Topics" hold references to items in other
+Fields like "Assigned To" and "Keywords" hold references to items in other
 classes ("user" and "keyword" in those two cases.)
 
 Sometimes, the selection is done through a menu, like in the "Assigned
@@ -130,13 +130,13 @@
   match issues that are not assigned to a user.
 ``assignedto=2,3,40``
   match issues that are assigned to users 2, 3 or 40.
-``topic=user interface``
-  match issues with the keyword "user interface" in their topic list
-``topic=web interface,e-mail interface``
+``keyword=user interface``
+  match issues with the keyword "user interface" in their keyword list
+``keyword=web interface,e-mail interface``
   match issues with the keyword "web interface" or "e-mail interface" in
-  their topic list
-``topic=-1``
-  match issues with no topics set
+  their keyword list
+``keyword=-1``
+  match issues with no keywords set
 
 
 Date properties
@@ -350,10 +350,10 @@
 (whitespace has been added for clarity)::
 
     /issue?status=unread,in-progress,resolved&
-        topic=security,ui&
+        keyword=security,ui&
         @group=priority,-status&
         @sort=-activity&
-        @filters=status,topic&
+        @filters=status,keyword&
         @columns=title,status,fixer
 
 
--- a/roundup/roundupdb.py	Fri Sep 14 15:55:25 2007 +0000
+++ b/roundup/roundupdb.py	Sun Sep 16 02:45:11 2007 +0000
@@ -16,7 +16,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 #
-# $Id: roundupdb.py,v 1.132 2007-09-10 19:18:31 forsberg Exp $
+# $Id: roundupdb.py,v 1.133 2007-09-16 02:45:11 jpend Exp $
 
 """Extending hyperdb with types specific to issue-tracking.
 """
@@ -142,10 +142,10 @@
     #
     # Note that this list also includes properties
     # defined in the classic template:
-    # assignedto, topic, priority, status.
+    # assignedto, keyword, priority, status.
     (
         ''"title", ''"messages", ''"files", ''"nosy", ''"superseder",
-        ''"assignedto", ''"topic", ''"priority", ''"status",
+        ''"assignedto", ''"keyword", ''"priority", ''"status",
         # following properties are common for all hyperdb classes
         # they are listed here to keep things in one place
         ''"actor", ''"activity", ''"creator", ''"creation",
--- a/scripts/import_sf.py	Fri Sep 14 15:55:25 2007 +0000
+++ b/scripts/import_sf.py	Sun Sep 16 02:45:11 2007 +0000
@@ -224,7 +224,7 @@
         d['creator'] = users[artifact['submitted_by']]
         actor = d['creator']
         if categories[artifact['category']]:
-            d['topic'] = [categories[artifact['category']]]
+            d['keyword'] = [categories[artifact['category']]]
         issue_journal.append((
             d['id'], d['creation'].get_tuple(), d['creator'], "'create'", {}
         ))
--- a/templates/classic/html/help_controls.js	Fri Sep 14 15:55:25 2007 +0000
+++ b/templates/classic/html/help_controls.js	Sun Sep 16 02:45:11 2007 +0000
@@ -1,4 +1,4 @@
-// initial values for either Nosy, Superseder, Topic and Waiting On,
+// initial values for either Nosy, Superseder, Keyword and Waiting On,
 // depending on which has called
 original_field = form[field].value;
 
--- a/templates/classic/html/issue.index.html	Fri Sep 14 15:55:25 2007 +0000
+++ b/templates/classic/html/issue.index.html	Sun Sep 16 02:45:11 2007 +0000
@@ -1,4 +1,4 @@
-<!-- $Id: issue.index.html,v 1.27 2006-11-09 01:26:28 richard Exp $ -->
+<!-- $Id: issue.index.html,v 1.28 2007-09-16 02:45:11 jpend Exp $ -->
 <tal:block metal:use-macro="templates/page/macros/icing">
 <title metal:fill-slot="head_title" >
   <span tal:omit-tag="true" i18n:translate="" >List of issues</span>
@@ -29,7 +29,7 @@
    <th tal:condition="request/show/creation" i18n:translate="">Creation</th>
    <th tal:condition="request/show/activity" i18n:translate="">Activity</th>
    <th tal:condition="request/show/actor" i18n:translate="">Actor</th>
-   <th tal:condition="request/show/topic" i18n:translate="">Topic</th>
+   <th tal:condition="request/show/keyword" i18n:translate="">Keyword</th>
    <th tal:condition="request/show/title" i18n:translate="">Title</th>
    <th tal:condition="request/show/status" i18n:translate="">Status</th>
    <th tal:condition="request/show/creator" i18n:translate="">Creator</th>
@@ -55,8 +55,8 @@
        tal:content="i/activity/reldate">&nbsp;</td>
    <td class="date" tal:condition="request/show/actor"
        tal:content="python:i.actor.plain() or default">&nbsp;</td>
-   <td tal:condition="request/show/topic"
-       tal:content="python:i.topic.plain() or default">&nbsp;</td>
+   <td tal:condition="request/show/keyword"
+       tal:content="python:i.keyword.plain() or default">&nbsp;</td>
    <td tal:condition="request/show/title">
     <a tal:attributes="href string:issue${i/id}"
 		tal:content="python:str(i.title.plain(hyperlink=0)) or '[no title]'">title</a>
--- a/templates/classic/html/issue.item.html	Fri Sep 14 15:55:25 2007 +0000
+++ b/templates/classic/html/issue.item.html	Sun Sep 16 02:45:11 2007 +0000
@@ -75,10 +75,10 @@
 <tr>
  <th i18n:translate="">Assigned To</th>
  <td tal:content="structure context/assignedto/menu">assignedto menu</td>
- <th i18n:translate="">Topics</th>
+ <th i18n:translate="">Keywords</th>
  <td>
-  <span tal:replace="structure context/topic/field" />
-  <span tal:condition="context/is_edit_ok" tal:replace="structure python:db.keyword.classhelp(property='topic')" />
+  <span tal:replace="structure context/keyword/field" />
+  <span tal:condition="context/is_edit_ok" tal:replace="structure python:db.keyword.classhelp(property='keyword')" />
  </td>
 </tr>
 
--- a/templates/classic/html/issue.search.html	Fri Sep 14 15:55:25 2007 +0000
+++ b/templates/classic/html/issue.search.html	Sun Sep 16 02:45:11 2007 +0000
@@ -50,10 +50,10 @@
   <td>&nbsp;</td>
 </tr>
 
-<tr tal:define="name string:topic;
+<tr tal:define="name string:keyword;
                 db_klass string:keyword;
                 db_content string:name;">
-  <th i18n:translate="">Topic:</th>
+  <th i18n:translate="">Keyword:</th>
   <td metal:use-macro="search_select">
     <option metal:fill-slot="extra_options" value="-1" i18n:translate=""
             tal:attributes="selected python:value == '-1'">not selected</option>
--- a/templates/classic/schema.py	Fri Sep 14 15:55:25 2007 +0000
+++ b/templates/classic/schema.py	Sun Sep 16 02:45:11 2007 +0000
@@ -71,7 +71,7 @@
 #   superseder = Multilink("issue")
 issue = IssueClass(db, "issue",
                 assignedto=Link("user"),
-                topic=Multilink("keyword"),
+                keyword=Multilink("keyword"),
                 priority=Link("priority"),
                 status=Link("status"))
 
--- a/templates/minimal/html/help_controls.js	Fri Sep 14 15:55:25 2007 +0000
+++ b/templates/minimal/html/help_controls.js	Sun Sep 16 02:45:11 2007 +0000
@@ -1,4 +1,4 @@
-// initial values for either Nosy, Superseder, Topic and Waiting On,
+// initial values for either Nosy, Superseder, Keyword and Waiting On,
 // depending on which has called
 original_field = form[field].value;
 
--- a/test/test_cgi.py	Fri Sep 14 15:55:25 2007 +0000
+++ b/test/test_cgi.py	Sun Sep 16 02:45:11 2007 +0000
@@ -8,7 +8,7 @@
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 #
-# $Id: test_cgi.py,v 1.31 2007-09-12 21:11:14 jpend Exp $
+# $Id: test_cgi.py,v 1.32 2007-09-16 02:45:11 jpend Exp $
 
 import unittest, os, shutil, errno, sys, difflib, cgi, re
 
@@ -213,8 +213,8 @@
         self.assertEqual(id,'1')
         id = self.db.keyword.create(name='1')
         self.assertEqual(id,'2')
-        issue = self.db.issue.create(title='i1-status1', topic=['1'])
-        self.assertEqual(self.db.issue.get(issue,'topic'),['1'])
+        issue = self.db.issue.create(title='i1-status1', keyword=['1'])
+        self.assertEqual(self.db.issue.get(issue,'keyword'),['1'])
         self.assertEqual(self.db.keyword.lookup('1'),'2')
         self.assertEqual(self.db.keyword.lookup('2'),'1')
         form = cgi.FieldStorage()
@@ -224,9 +224,9 @@
         cl.db = self.db
         cl.userid = '1'
         item = HTMLItem(cl, 'issue', issue)
-        for topic in item.topic:
-            self.assertEqual(topic.id, '1')
-            self.assertEqual(topic.name, '2')
+        for keyword in item.keyword:
+            self.assertEqual(keyword.id, '1')
+            self.assertEqual(keyword.name, '2')
 
     def testFileUpload(self):
         file = FileUpload('foo', 'foo.txt')

Roundup Issue Tracker: http://roundup-tracker.org/