Code

fixes to time tracking customisation
[roundup.git] / doc / customizing.txt
index 60ec72115ee1308d2091910cc0c50619ef19093b..eb6b8adceeed1c70a49388a0f576c9aea12d2d35 100644 (file)
@@ -2,7 +2,7 @@
 Customising Roundup
 ===================
 
-:Version: $Revision: 1.61 $
+:Version: $Revision: 1.72 $
 
 .. This document borrows from the ZopeBook section on ZPT. The original is at:
    http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
@@ -107,13 +107,25 @@ The configuration variables available are:
  The email address that e-mail sent to roundup should go to. Think of it as the
  tracker's personal e-mail address.
 
-**TRACKER_WEB** - ``'http://your.tracker.url.example/'``
+**TRACKER_WEB** - ``'http://tracker.example/cgi-bin/roundup.cgi/bugs/'``
  The web address that the tracker is viewable at. This will be included in
- information sent to users of the tracker.
+ information sent to users of the tracker. The URL **must** include the
+ cgi-bin part or anything else that is required to get to the home page of
+ the tracker. You **must** include a trailing '/' in the URL.
 
 **ADMIN_EMAIL** - ``'roundup-admin@%s'%MAIL_DOMAIN``
  The email address that roundup will complain to if it runs into trouble.
 
+**EMAIL_FROM_TAG** - ``''``
+ Additional text to include in the "name" part of the ``From:`` address used
+ in nosy messages. If the sending user is "Foo Bar", the ``From:`` line is
+ usually::
+     "Foo Bar" <issue_tracker@tracker.example>
+
+ the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so::
+
+    "Foo Bar EMAIL_FROM_TAG" <issue_tracker@tracker.example>
+
 **MESSAGES_TO_AUTHOR** - ``'yes'`` or``'no'``
  Send nosy messages to the author of the message.
 
@@ -170,12 +182,22 @@ tracker is attempted.::
     # The email address that mail to roundup should go to
     TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
 
-    # The web address that the tracker is viewable at
-    TRACKER_WEB = 'http://your.tracker.url.example/'
+    # The web address that the tracker is viewable at. This will be included in
+    # information sent to users of the tracker. The URL MUST include the cgi-bin
+    # part or anything else that is required to get to the home page of the
+    # tracker. You MUST include a trailing '/' in the URL.
+    TRACKER_WEB = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/'
 
     # The email address that roundup will complain to if it runs into trouble
     ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
 
+    # Additional text to include in the "name" part of the From: address used
+    # in nosy messages. If the sending user is "Foo Bar", the From: line is
+    # usually: "Foo Bar" <issue_tracker@tracker.example>
+    # the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so:
+    #    "Foo Bar EMAIL_FROM_TAG" <issue_tracker@tracker.example>
+    EMAIL_FROM_TAG = ""
+
     # Send nosy messages to the author of the message
     MESSAGES_TO_AUTHOR = 'no'           # either 'yes' or 'no'
 
@@ -206,6 +228,14 @@ tracker is attempted.::
     MAIL_DEFAULT_CLASS = 'issue'   # use "issue" class by default
     #MAIL_DEFAULT_CLASS = ''        # disable (or just comment the var out)
 
+    # 
+    # SECURITY DEFINITIONS
+    #
+    # define the Roles that a user gets when they register with the tracker
+    # these are a comma-separated string of role names (e.g. 'Admin,User')
+    NEW_WEB_USER_ROLES = 'User'
+    NEW_EMAIL_USER_ROLES = 'User'
+
 Tracker Schema
 ==============
 
@@ -437,9 +467,12 @@ case though, so be careful to use the right one.
     the create() methods.
 
 **Changing content after tracker initialisation**
-    Use the roundup-admin interface's create, set and retire methods to add,
-    alter or remove items from the classes in question.
+    As the "admin" user, click on the "class list" link in the web interface
+    to bring up a list of all database classes. Click on the name of the class
+    you wish to change the content of.
 
+    You may also use the roundup-admin interface's create, set and retire
+    methods to add, alter or remove items from the classes in question.
 
 See "`adding a new field to the classic schema`_" for an example that requires
 database content changes.
@@ -585,6 +618,16 @@ Example Scenarios
  normal "User" Role minus the "Web Access" Permission. This will allow users
  to send in emails to the tracker, but not access the web interface.
 
+**let some users edit the details of all users**
+ Create a new Role called "User Admin" which has the Permission for editing
+ users::
+
+    db.security.addRole(name='User Admin', description='Managing users')
+    p = db.security.getPermission('Edit', 'user')
+    db.security.addPermissionToRole('User Admin', p)
+
+ and assign the Role to the users who need the permission.
+
 
 Web Interface
 =============
@@ -718,6 +761,12 @@ triggered by using a ``:action`` CGI variable, where the value is one of:
   the :note if it's supplied.
  :required=property,property,...
   The named properties are required to be filled in the form.
+ :remove:<propname>=id(s)
+  The ids will be removed from the multilink property. You may have multiple
+  :remove:<propname> form elements for a single <propname>.
+ :add:<propname>=id(s)
+  The ids will be added to the multilink property. You may have multiple
+  :add:<propname> form elements for a single <propname>.
 
 **new**
  Add a new item to the database. You may use the same special form elements
@@ -950,7 +999,7 @@ forms:
    in place if the "foo" form variable doesn't exist.
 
 **String Expressions** - eg. ``string:hello ${user/name}``
-   These expressions are simple string interpolations (though they can be just
+   These expressions are simple string interpolations though they can be just
    plain strings with no interpolation if you want. The expression in the
    ``${ ... }`` is just a path expression as above.
 
@@ -1030,7 +1079,6 @@ The following variables are available to templates.
   `hyperdb class wrapper`_ or a `hyperdb item wrapper`_
 **request**
   Includes information about the current request, including:
-   - the url
    - the current index information (``filterspec``, ``filter`` args,
      ``properties``, etc) parsed out of the form. 
    - methods for easy filterspec link generation
@@ -1193,35 +1241,64 @@ The property wrapper has some useful attributes:
 Attribute       Description
 =============== =============================================================
 _name           the name of the property
-_value          the value of the property if any
+_value          the value of the property if any - this is the actual value
+                retrieved from the hyperdb for this property
 =============== =============================================================
 
 There are several methods available on these wrapper objects:
 
-=========== =================================================================
-Method      Description
-=========== =================================================================
-plain       render a "plain" representation of the property
-field       render a form edit field for the property
-stext       only on String properties - render the value of the
-            property as StructuredText (requires the StructureText module
-            to be installed separately)
-multiline   only on String properties - render a multiline form edit
-            field for the property
-email       only on String properties - render the value of the 
-            property as an obscured email address
-confirm     only on Password properties - render a second form edit field for
-            the property, used for confirmation that the user typed the
-            password correctly. Generates a field with name "name:confirm".
-reldate     only on Date properties - render the interval between the
-            date and now
-pretty      only on Interval properties - render the interval in a
-            pretty format (eg. "yesterday")
-menu        only on Link and Multilink properties - render a form select
-            list for this property
-reverse     only on Multilink properties - produce a list of the linked
-            items in reverse order
-=========== =================================================================
+========= =====================================================================
+Method    Description
+========= =====================================================================
+plain     render a "plain" representation of the property. This method may
+          take two arguments:
+
+          escape
+           If true, escape the text so it is HTML safe (default: no). The
+           reason this defaults to off is that text is usually escaped
+           at a later stage by the TAL commands, unless the "structure"
+           option is used in the template. The following are all equivalent::
+
+            <p tal:content="structure python:msg.content.plain(escape=1)" />
+            <p tal:content="python:msg.content.plain()" />
+            <p tal:content="msg/content/plain" />
+            <p tal:content="msg/content" />
+
+           Usually you'll only want to use the escape option in a complex
+           expression.
+
+          hyperlink
+           If true, turn URLs, email addresses and hyperdb item designators
+           in the text into hyperlinks (default: no). Note that you'll need
+           to use the "structure" TAL option if you want to use this::
+
+            <p tal:content="structure python:msg.content.plain(hyperlink=1)" />
+
+           Note also that the text is automatically HTML-escape before the
+           hyperlinking transformation.
+
+field     render an appropriate form edit field for the property - for most
+          types this is a text entry box, but for Booleans it's a tri-state
+          yes/no/neither selection.
+stext     only on String properties - render the value of the
+          property as StructuredText (requires the StructureText module
+          to be installed separately)
+multiline only on String properties - render a multiline form edit
+          field for the property
+email     only on String properties - render the value of the 
+          property as an obscured email address
+confirm   only on Password properties - render a second form edit field for
+          the property, used for confirmation that the user typed the
+          password correctly. Generates a field with name "name:confirm".
+reldate   only on Date properties - render the interval between the
+          date and now
+pretty    only on Interval properties - render the interval in a
+          pretty format (eg. "yesterday")
+menu      only on Link and Multilink properties - render a form select
+          list for this property
+reverse   only on Multilink properties - produce a list of the linked
+          items in reverse order
+========= =====================================================================
 
 The request variable
 ~~~~~~~~~~~~~~~~~~~~
@@ -1237,7 +1314,6 @@ Variable    Holds
 =========== =================================================================
 form        the CGI form as a cgi.FieldStorage
 env         the CGI environment variables
-url         the current URL path for this request
 base        the base URL for this tracker
 user        a HTMLUser instance for this user
 classname   the current classname (possibly None)
@@ -1474,6 +1550,10 @@ the "status" and "topic" properties, and the table includes columns for the
 Searching Views
 ---------------
 
+Note: if you add a new column to the ``:columns`` form variable potentials
+      then you will need to add the column to the appropriate `index views`_
+      template so it is actually displayed.
+
 This is one of the class context views. The template used is typically
 "*classname*.search". The form on this page should have "search" as its
 ``:action`` variable. The "search" action:
@@ -1503,7 +1583,6 @@ action are:
   template schema does not.
 
 
-
 Item Views
 ----------
 
@@ -2144,26 +2223,23 @@ to.
    which displays only the allowed status to transition to.
 
 
-Displaying entire message contents in the issue display
--------------------------------------------------------
+Displaying only message summaries in the issue display
+------------------------------------------------------
 
 Alter the issue.item template section for messages to::
 
  <table class="messages" tal:condition="context/messages">
-  <tr><th colspan=3 class="header">Messages</th></tr>
-  <tal:block tal:repeat="msg context/messages/reverse">
-   <tr>
-    <th><a tal:attributes="href string:msg${msg/id}"
-           tal:content="string:msg${msg/id}"></a></th>
-    <th tal:content="string:Author: ${msg/author}">author</th>
-    <th tal:content="string:Date: ${msg/date}">date</th>
-   </tr>
-   <tr>
-    <td colspan="3" class="content">
-     <pre tal:content="msg/content">content</pre>
-    </td>
-   </tr>
-  </tal:block>
+  <tr><th colspan=5 class="header">Messages</th></tr>
+  <tr tal:repeat="msg context/messages">
+   <td><a tal:attributes="href string:msg${msg/id}"
+          tal:content="string:msg${msg/id}"></a></td>
+   <td tal:content="msg/author">author</td>
+   <td nowrap tal:content="msg/date/pretty">date</td>
+   <td tal:content="msg/summary">summary</td>
+   <td>
+    <a tal:attributes="href string:?:remove:messages=${msg/id}&:action=edit">remove</a>
+   </td>
+  </tr>
  </table>
 
 Restricting the list of users that are assignable to a task
@@ -2476,44 +2552,66 @@ able to give a summary of the total time spent on a particular issue.
 
    The code to do this is::
 
-    actions = client.Client.actions + (
-        ('edit_with_timelog', 'timelogEditAction'),
-    )
+    class Client(client.Client): 
+        ''' derives basic CGI implementation from the standard module, 
+            with any specific extensions 
+        ''' 
+        actions = client.Client.actions + (
+            ('edit_with_timelog', 'timelogEditAction'),
+        )
+
+        def timelogEditAction(self):
+            ''' Handle the creation of a new time log entry if necessary.
+
+                If we create a new entry, fake up a CGI form value for the
+                altered "times" property of the issue being edited.
+   
+                Punt to the regular edit action when we're done.
+            '''
+            # if there's a timelog value specified, create an entry
+            if self.form.has_key(':timelog') and \
+                    self.form[':timelog'].value.strip():
+                period = Interval(self.form[':timelog'].value)
+                # create it
+                newid = self.db.timelog.create(period=period)
+
+                # if we're editing an existing item, get the old timelog value
+                if self.nodeid:
+                    l = self.db.issue.get(self.nodeid, 'times')
+                    l.append(newid)
+                else:
+                    l = [newid]
 
-    def timelogEditAction(self):
-        ''' Handle the creation of a new time log entry if necessary.
+                # now make the fake CGI form values
+                for entry in l:
+                    self.form.list.append(MiniFieldStorage('times', entry))
 
-            If we create a new entry, fake up a CGI form value for the altered
-            "times" property of the issue being edited.
+            # punt to the normal edit action
+            return self.editItemAction()
+   
+   you add this code to your Client class in your tracker's ``interfaces.py``
+   file. Locate the section that looks like::
 
-            Punt to the regular edit action when we're done.
-        '''
-        # if there's a timelog value specified, create an entry
-        if self.form.has_key(':timelog') and \
-                self.form[':timelog'].value.strip():
-            period = Interval(self.form[':timelog'].value)
-            # create it
-            newid = self.db.timelog.create(period=period)
-
-            # if we're editing an existing item, get the old timelog value
-            if self.nodeid:
-                l = self.db.issue.get(self.nodeid, 'times')
-                l.append(newid)
-            else:
-                l = [newid]
-
-            # now make the fake CGI form values
-            for entry in l:
-                self.form.list.append(MiniFieldStorage('times', entry))
-
-        # punt to the normal edit action
-        return self.editItemAction()
+    class Client:
+        ''' derives basic CGI implementation from the standard module, 
+            with any specific extensions 
+        ''' 
+        pass
 
-   you add this code to your Client class in your tracker's ``interfaces.py``
-   file.
+   and insert this code in place of the ``pass`` statement.
 
 5. You'll also need to modify your ``issue.item`` form submit action so it
-   calls the time logging action we just created::
+   calls the time logging action we just created. The current template will
+   look like this::
+
+    <tr>
+     <td>&nbsp;</td>
+     <td colspan=3 tal:content="structure context/submit">
+      submit button will go here
+     </td>
+    </tr>
+
+   replace it with this::
 
     <tr>
      <td>&nbsp;</td>
@@ -2529,9 +2627,8 @@ able to give a summary of the total time spent on a particular issue.
      </td>
     </tr>
 
-   Note that the "context/submit" command usually handles all that for you -
-   isn't it handy? The important change is setting the action to
-   "edit_with_timelog" for edit operations (where the item exists)
+   The important change is setting the action to "edit_with_timelog" for
+   edit operations (where the item exists)
 
 6. We want to display a total of the time log times that have been accumulated
    for an issue. To do this, we'll need to actually write some Python code,
@@ -2539,7 +2636,6 @@ able to give a summary of the total time spent on a particular issue.
    We do this by adding a method to the TemplatingUtils class in our tracker
    ``interfaces.py`` module::
 
-
     class TemplatingUtils:
         ''' Methods implemented on this class will be available to HTML
             templates through the 'utils' variable.
@@ -2553,8 +2649,9 @@ able to give a summary of the total time spent on a particular issue.
                 total += time.period._value
             return total
 
+   Replace the ``pass`` line as we did in step 4 above with the Client class.
    As indicated in the docstrings, we will be able to access the
-   ``totalTimeSpent`` method via the ``utils`` variable in our templates. See
+   ``totalTimeSpent`` method via the ``utils`` variable in our templates.
 
 7. Display the time log for an issue::
 
@@ -2718,7 +2815,7 @@ Enabling display of either message summaries or the entire messages
 -------------------------------------------------------------------
 
 This is pretty simple - all we need to do is copy the code from the example
-`displaying entire message contents in the issue display`_ into our template
+`displaying only message summaries in the issue display`_ into our template
 alongside the summary display, and then introduce a switch that shows either
 one or the other. We'll use a new form variable, ``:whole_messages`` to
 achieve this::