|
2 | 2 | Customising Roundup |
3 | 3 | =================== |
4 | 4 |
|
5 | | -:Version: $Revision: 1.97 $ |
| 5 | +:Version: $Revision: 1.98 $ |
6 | 6 |
|
7 | 7 | .. This document borrows from the ZopeBook section on ZPT. The original is at: |
8 | 8 | http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx |
@@ -3349,6 +3349,172 @@ on it (i.e. it's in their blockers list) you can look at the journal |
3349 | 3349 | history at the bottom of the issue page - look for a "link" event to |
3350 | 3350 | another issue's "blockers" property. |
3351 | 3351 |
|
| 3352 | +Add users to the nosy list based on the topic |
| 3353 | +--------------------------------------------- |
| 3354 | + |
| 3355 | +We need the ability to automatically add users to the nosy list based |
| 3356 | +on the occurence of a topic. Every user should be allowed to edit his |
| 3357 | +own list of topics for which he wants to be added to the nosy list. |
| 3358 | + |
| 3359 | +Below will be showed that such a change can be performed with only |
| 3360 | +minimal understanding of the roundup system, but with clever use |
| 3361 | +of Copy and Paste. |
| 3362 | + |
| 3363 | +This requires three changes to the tracker: a change in the database to |
| 3364 | +allow per-user recording of the lists of topics for which he wants to |
| 3365 | +be put on the nosy list, a change in the user view allowing to edit |
| 3366 | +this list of topics, and addition of an auditor which updates the nosy |
| 3367 | +list when a topic is set. |
| 3368 | + |
| 3369 | +Adding the nosy topic list |
| 3370 | +~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 3371 | + |
| 3372 | +The change in the database to make is that for any user there should be |
| 3373 | +a list of topics for which he wants to be put on the nosy list. Adding |
| 3374 | +a ``Multilink`` of ``keyword`` seem to fullfill this (note that within |
| 3375 | +the code topics are called ``keywords``.) As such, all what has to be |
| 3376 | +done is to add a new field to the definition of ``user`` within the |
| 3377 | +file ``dbinit.py``. We will call this new field ``nosy_keywords``, and |
| 3378 | +the updated definition of user will be:: |
| 3379 | + |
| 3380 | + user = Class(db, "user", |
| 3381 | + username=String(), password=Password(), |
| 3382 | + address=String(), realname=String(), |
| 3383 | + phone=String(), organisation=String(), |
| 3384 | + alternate_addresses=String(), |
| 3385 | + queries=Multilink('query'), roles=String(), |
| 3386 | + timezone=String(), |
| 3387 | + nosy_keywords=Multilink('keyword')) |
| 3388 | + |
| 3389 | +Changing the user view to allow changing the nosy topic list |
| 3390 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 3391 | + |
| 3392 | +We want any user to be able to change the list of topics for which |
| 3393 | +he will by default be added to the nosy list. We choose to add this |
| 3394 | +to the user view, as is generated by the file ``html/user.item.html``. |
| 3395 | +We easily can |
| 3396 | +see that the topic field in the issue view has very similar editting |
| 3397 | +requirements as our nosy topics, both being a list of topics. As |
| 3398 | +such, we search for Topics in ``issue.item.html``, and extract the |
| 3399 | +associated parts from there. We add this to ``user.item.html`` at the |
| 3400 | +bottom of the list of viewed items (i.e. just below the 'Alternate |
| 3401 | +E-mail addresses' in the classic template):: |
| 3402 | + |
| 3403 | + <tr> |
| 3404 | + <th>Nosy Topics</th> |
| 3405 | + <td> |
| 3406 | + <span tal:replace="structure context/nosy_keywords/field" /> |
| 3407 | + <span tal:replace="structure python:db.keyword.classhelp(property='nosy_keywords')" /> |
| 3408 | + </td> |
| 3409 | + </tr> |
| 3410 | + |
| 3411 | + |
| 3412 | +Addition of an auditor to update the nosy list |
| 3413 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 3414 | + |
| 3415 | +The more difficult part is the addition of the logic to actually |
| 3416 | +at the users to the nosy list when it is required. |
| 3417 | +The choice is made to perform this action when the topics on an |
| 3418 | +item are set, including when an item is created. |
| 3419 | +Here we choose to start out with a copy of the |
| 3420 | +``detectors/nosyreaction.py`` detector, which we copy to the file |
| 3421 | +``detectors/nosy_keyword_reaction.py``. |
| 3422 | +This looks like a good start as it also adds users |
| 3423 | +to the nosy list. A look through the code reveals that the |
| 3424 | +``nosyreaction`` function actually is sending the e-mail, which |
| 3425 | +we do not need. As such, we can change the init function to:: |
| 3426 | + |
| 3427 | + def init(db): |
| 3428 | + db.issue.audit('create', update_kw_nosy) |
| 3429 | + db.issue.audit('set', update_kw_nosy) |
| 3430 | + |
| 3431 | +After that we rename the ``updatenosy`` function to ``update_kw_nosy``. |
| 3432 | +The first two blocks of code in that function relate to settings |
| 3433 | +``current`` to a combination of the old and new nosy lists. This |
| 3434 | +functionality is left in the new auditor. The following block of |
| 3435 | +code, which in ``updatenosy`` handled adding the assignedto user(s) |
| 3436 | +to the nosy list, should be replaced by a block of code to add the |
| 3437 | +interested users to the nosy list. We choose here to loop over all |
| 3438 | +new topics, than loop over all users, |
| 3439 | +and assign the user to the nosy list when the topic in the user's |
| 3440 | +nosy_keywords. The next part in ``updatenosy``, adding the author |
| 3441 | +and/or recipients of a message to the nosy list, obviously is not |
| 3442 | +relevant here and thus is deleted from the new auditor. The last |
| 3443 | +part, copying the new nosy list to newvalues, does not have to be changed. |
| 3444 | +This brings the following function:: |
| 3445 | + |
| 3446 | + def update_kw_nosy(db, cl, nodeid, newvalues): |
| 3447 | + '''Update the nosy list for changes to the topics |
| 3448 | + ''' |
| 3449 | + # nodeid will be None if this is a new node |
| 3450 | + current = {} |
| 3451 | + if nodeid is None: |
| 3452 | + ok = ('new', 'yes') |
| 3453 | + else: |
| 3454 | + ok = ('yes',) |
| 3455 | + # old node, get the current values from the node if they haven't |
| 3456 | + # changed |
| 3457 | + if not newvalues.has_key('nosy'): |
| 3458 | + nosy = cl.get(nodeid, 'nosy') |
| 3459 | + for value in nosy: |
| 3460 | + if not current.has_key(value): |
| 3461 | + current[value] = 1 |
| 3462 | + |
| 3463 | + # if the nosy list changed in this transaction, init from the new value |
| 3464 | + if newvalues.has_key('nosy'): |
| 3465 | + nosy = newvalues.get('nosy', []) |
| 3466 | + for value in nosy: |
| 3467 | + if not db.hasnode('user', value): |
| 3468 | + continue |
| 3469 | + if not current.has_key(value): |
| 3470 | + current[value] = 1 |
| 3471 | + |
| 3472 | + # add users with topic in nosy_keywords to the nosy list |
| 3473 | + if newvalues.has_key('topic') and newvalues['topic'] is not None: |
| 3474 | + topic_ids = newvalues['topic'] |
| 3475 | + for topic in topic_ids: |
| 3476 | + # loop over all users, |
| 3477 | + # and assign user to nosy when topic in nosy_keywords |
| 3478 | + for user_id in db.user.list(): |
| 3479 | + nosy_kw = db.user.get(user_id, "nosy_keywords") |
| 3480 | + found = 0 |
| 3481 | + for kw in nosy_kw: |
| 3482 | + if kw == topic: |
| 3483 | + found = 1 |
| 3484 | + if found: |
| 3485 | + current[user_id] = 1 |
| 3486 | + |
| 3487 | + # that's it, save off the new nosy list |
| 3488 | + newvalues['nosy'] = current.keys() |
| 3489 | + |
| 3490 | +and these two function are the only ones needed in the file. |
| 3491 | + |
| 3492 | +TODO: update this example to use the find() Class method. |
| 3493 | + |
| 3494 | +Caveats |
| 3495 | +~~~~~~~ |
| 3496 | + |
| 3497 | +A few problems with the design here can be noted: |
| 3498 | + |
| 3499 | +Multiple additions |
| 3500 | + When a user, after automatic selection, is manually removed |
| 3501 | + from the nosy list, he again is added to the nosy list when the |
| 3502 | + topic list of the issue is updated. A better design might be |
| 3503 | + to only check which topics are new compared to the old list |
| 3504 | + of topics, and only add users when they have indicated |
| 3505 | + interest on a new topic. |
| 3506 | + |
| 3507 | + The code could also be changed to only trigger on the create() event, |
| 3508 | + rather than also on the set() event, thus only setting the nosy list |
| 3509 | + when the issue is created. |
| 3510 | + |
| 3511 | +Scalability |
| 3512 | + In the auditor there is a loop over all users. For a site with |
| 3513 | + only few users this will pose no serious problem, however, with |
| 3514 | + many users this will be a serious performance bottleneck. |
| 3515 | + A way out will be to link from the topics to the users which |
| 3516 | + selected these topics a nosy topics. This will eliminate the |
| 3517 | + loop over all users. |
3352 | 3518 |
|
3353 | 3519 | ------------------- |
3354 | 3520 |
|
|
0 commit comments