Log note :
changed:
-
This is a combination of a reactor that creates a static template file including all the users and an example how to make use of the created template.
The solution was initially developed by Marcus Priesch -- I'm just documenting it, since the mailinglist archives are unavailable from time to time::

 import os
 import shutil
 pjoin = os.path.join
 from roundup.cgi.TranslationService import get_translation
 from tempfile                       import mkstemp
 from roundup.date                   import Date
 from roundup.exceptions             import Reject
 USER_SINGLE = """
 <tal:block metal:define-macro="%(macro_name)s">
  <tal:block tal:condition="python:not context [name].is_edit_ok ()"
   tal:replace="python: context [name]"/>
  <select tal:attributes="name name"
   tal:condition="python: context [name].is_edit_ok ()">
   <option value=""
           tal:content="dont_care"></option>
   <!-- autogenerated -->
 %(option_list)s
   <!-- autogenerated -->
 </select>
 &lt;disabled script language="javascript"
         tal:content="structure string:
 <!--
 select_box = document.${form}.${name};
 for (i = 0; i < select_box.length; i++)
   {
     if (select_box.options [i].value == ${selected})
       select_box.options [i].selected = true;
     else
       select_box.options [i].selected = false;
   }
 --&gt;
 ">&lt;disabled /script&gt;
 </tal:block>
 """
 
 USER_MULTI = """
 <tal:block metal:define-macro="%(macro_name)s">
  <tal:block tal:condition="python:not %(condition)s"
   tal:replace="python: context [name]"/>
  <select multiple tal:condition="python: %(condition)s"
          tal:attributes="size size;
                          name name">
   <option value=""
           tal:content="dont_care"></option>
   <!-- autogenerated -->
 %(option_list)s
   <!-- autogenerated -->
 </select>
 &lt;disabled script language="javascript"
         tal:content="structure string:
 <!--
 select_box = document.${form}.${name};
 selected   = new Array (${selected});
 for (i = 0; i < select_box.length; i++)
   {
     for (j = 0; j < selected.length; j++)
       {
         if (select_box.options [i].value == selected [j])
           select_box.options [i].selected = true;
       }
   }
 --&gt;
 ">&lt;disabled /script&gt;
 </tal:block>
 """
 
 OPTION_FMT = """  <option value="%s">%s</option>"""
 
 def update_userlist_html (db, cl, nodeid, old_values) :
     """newly create user_list.html macro page
     """
     root       = pjoin (db.config.TRACKER_HOME, "html")
     userlist   = "userlist.html"
     changed    = False
     for i in 'username', 'status', 'roles' :
         if  (  not old_values
             or i not in old_values
             or old_values [i] != cl.get (nodeid, i)
             ) :
             changed = True
     if not changed :
         return
     f, tmpname = mkstemp (".html", "userlist", root)
     f          = os.fdopen (f, "w")
     # all 'real' users
     spec = {}
     if 'status' in cl.properties :
         valid = db.user_status.lookup ('valid')
         spec  = { 'status' : [valid] }
     users      = cl.filter ( None # full text search
                            , filterspec = spec
                            , sort       = ("+", "username")
                            )
     if users :
         options  = [OPTION_FMT % (id, cl.get (id, "username")) for id in users] 
 
         f.write (USER_SINGLE % { "macro_name"  : "user"
                                , "option_list" : "\n".join (options)
                                }
                 )
         f.write (USER_MULTI  % { "macro_name"  : "user_multi"
                                , "option_list" : "\n".join (options)
                                , "condition"   : "context [name].is_edit_ok ()"
                                }
                 )
         f.write (USER_MULTI  % { "macro_name"  : "user_multi_read"
                                , "option_list" : "\n".join (options)
                                , "condition"   : "True"
                                }
                 )
 
     # all users (incl. mail alias users)
     # RSC: now there are no mail alias users -- and we don't want
     # invalid users here, so use the same filterspec.
     spec = {}
     if 'status' in cl.properties :
         status = [db.user_status.lookup (s) for s in 'valid', 'system']
         spec   = {"status" : status}
     users    = cl.filter ( None # full text search
                          , filterspec = spec
                          , sort       = ("+", "username")
                          )
     if users :
         options  = [OPTION_FMT % (id, cl.get (id, "username")) for id in users]

         f.write (USER_MULTI  % { "macro_name"  : "nosy_multi"
                                , "option_list" : "\n".join (options)
                                , "condition"   : "True"
                                }
                 )

     f.close ()
     shutil.move (tmpname, pjoin (root, userlist))
 # end def update_userlist_html

-

 Note that the example above assumes a "status" attribute of the user class that is not present in the standard tracker. Furthermore we originally hat special alias-users that were permitted on the nosy-list but not permitted as the responsible person for an issue. So if anybody simplifies this code to work with the roundup standard tracker, it would be nice if the result is shared on this page.

 How to use it in html templates, the macro has four parameters:

 - name: the name of the cgi variable

 - form: the name of the form

 - dont_care: whats displayed as "dont care which user"

 - selected: the id which gets automatically selected

The following example is a roundup link-attribute, the "supervisor" field of the user class (the utils.fieldname utility function creates the localised field name with a link to a documentation popup in our implementation)::

 <tr>
  <th tal:content="structure python:utils.fieldname('user', 'supervisor')"/>
  <td>
   <tal:block tal:define="name      string:supervisor;
                          form      string:user_form;
                          dont_care string:don't care;
                          selected  context/supervisor/id | string:0">
    <tal:block metal:use-macro="templates/userlist/macros/user"></tal:block>
   </tal:block>
  </td>
 </tr>

The following example is for a multilink-property called 'authors'::

    <tr>
     <th class="required"
      tal:content="structure python:utils.fieldname (classname, 'authors')" />
     <td colspan="3">
      <tal:block tal:define="size      string:3;
                             name      string:authors;
                             form      string:itemSynopsis;
                             dont_care string:don't care;
                             selected  python:str([u.id for u in context.authors.reverse ()] or [''])[1:-1]">
       <tal:block metal:use-macro="templates/userlist/macros/user_multi"></tal:block>
      </tal:block>
     </td>
    </tr>