Mercurial > p > roundup > code
diff doc/customizing.txt @ 1808:3ac35c8e1782
new example and some more installation docs
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Fri, 12 Sep 2003 04:29:35 +0000 |
| parents | a3b1b1dcf639 |
| children | 61a23c293147 |
line wrap: on
line diff
--- a/doc/customizing.txt Wed Sep 10 13:04:05 2003 +0000 +++ b/doc/customizing.txt Fri Sep 12 04:29:35 2003 +0000 @@ -2,7 +2,7 @@ Customising Roundup =================== -:Version: $Revision: 1.97 $ +:Version: $Revision: 1.98 $ .. This document borrows from the ZopeBook section on ZPT. The original is at: http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx @@ -3349,6 +3349,172 @@ 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 +--------------------------------------------- + +We need the ability to automatically add users to the nosy list based +on the occurence of a topic. Every user should be allowed to edit his +own list of topics for which he wants to be added to the nosy list. + +Below will be showed that such a change can be performed with only +minimal understanding of the roundup system, but with clever use +of 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 +be put on the nosy list, a change in the user view allowing 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 in the database to make 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`` seem to fullfill this (note that within +the code topics are called ``keywords``.) As such, all what has to be +done is to add a new field to the definition of ``user`` within the +file ``dbinit.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(), + address=String(), realname=String(), + phone=String(), organisation=String(), + alternate_addresses=String(), + queries=Multilink('query'), roles=String(), + 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 +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 easily can +see that the topic field in the issue view has very similar editting +requirements as our nosy topics, both being a list of topics. As +such, we search for Topics 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> + <td> + <span tal:replace="structure context/nosy_keywords/field" /> + <span tal:replace="structure python:db.keyword.classhelp(property='nosy_keywords')" /> + </td> + </tr> + + +Addition of an auditor to update the nosy list +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The more difficult part is the addition of the logic to actually +at the users to the nosy list when it is required. +The choice is made to perform this action when the topics on an +item are set, including when an item is created. +Here we choose to start out with a copy of the +``detectors/nosyreaction.py`` detector, which we copy to the file +``detectors/nosy_keyword_reaction.py``. +This looks like a good start as it also adds users +to the nosy list. A look through the code reveals that the +``nosyreaction`` function actually is sending the e-mail, which +we do not need. As such, we can change the init function to:: + + def init(db): + db.issue.audit('create', update_kw_nosy) + db.issue.audit('set', update_kw_nosy) + +After that we rename the ``updatenosy`` function to ``update_kw_nosy``. +The first two blocks of code in that function relate to settings +``current`` to a combination of the old and new nosy lists. This +functionality is left in the new auditor. The following block of +code, which in ``updatenosy`` handled adding the assignedto user(s) +to the nosy list, 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 loop over all users, +and assign the user to the nosy list when the topic in the user's +nosy_keywords. The next part in ``updatenosy``, adding the author +and/or recipients of a message to the nosy list, obviously is not +relevant here and thus is deleted from the new auditor. The last +part, copying the new nosy list to newvalues, does not have to be changed. +This brings the following function:: + + def update_kw_nosy(db, cl, nodeid, newvalues): + '''Update the nosy list for changes to the topics + ''' + # nodeid will be None if this is a new node + current = {} + if nodeid is None: + ok = ('new', 'yes') + else: + ok = ('yes',) + # old node, get the current values from the node if they haven't + # changed + if not newvalues.has_key('nosy'): + nosy = cl.get(nodeid, 'nosy') + for value in nosy: + if not current.has_key(value): + current[value] = 1 + + # if the nosy list changed in this transaction, init from the new value + if newvalues.has_key('nosy'): + nosy = newvalues.get('nosy', []) + for value in nosy: + if not db.hasnode('user', value): + continue + 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: + # loop over all users, + # and assign user to nosy when topic 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: + found = 1 + if found: + current[user_id] = 1 + + # that's it, save off the new nosy list + newvalues['nosy'] = current.keys() + +and these two function are the only ones needed in the file. + +TODO: update this example to use the find() Class method. + +Caveats +~~~~~~~ + +A few problems with the design here can be noted: + +Multiple additions + When a user, after automatic selection, is manually removed + from the nosy list, he again is added to the nosy list 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. + + The code could also be changed to only trigger on the create() event, + rather than also on the set() event, thus only setting the nosy list + when the issue is created. + +Scalability + 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 will be to link from the topics to the users which + selected these topics a nosy topics. This will eliminate the + loop over all users. -------------------
