Code

Added users' timezone support
authorkedder <kedder@57a73879-2fb5-44c3-a270-3262357dd7e2>
Mon, 27 Jan 2003 16:32:50 +0000 (16:32 +0000)
committerkedder <kedder@57a73879-2fb5-44c3-a270-3262357dd7e2>
Mon, 27 Jan 2003 16:32:50 +0000 (16:32 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1480 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
doc/upgrading.txt
roundup/cgi/client.py
roundup/cgi/templating.py
roundup/mailgw.py
roundup/roundupdb.py
roundup/templates/classic/dbinit.py
roundup/templates/classic/html/user.item

index d9802b62d1f2ee41b056934daabdd825e7bb0c07..1d3c15d595d2023c9636a5add0b10cdaf990b0c1 100644 (file)
@@ -23,6 +23,8 @@ are given with the most recent entry first.
   according to rfc2822 (sf bug 568873)
 - fixed cookie path to use TRACKER_WEB (sf bug 667020) (thanks Nathaniel Smith
   for helping chase it down and Luke Opperman for confirming fix)
+- added ability to display localized dates in web interface. User input is
+  convered to GMT (see doc/upgrading.txt).
 
 
 2003-??-?? 0.5.5
index a7a6096588d8bf0e7c3edcc81fa528939e12ae5f..e4c77cfd34cfdf443f3d87821ae7221426fccf0d 100644 (file)
@@ -46,6 +46,40 @@ Migrating from 0.5 to 0.6
   is no tool for converting such data, the only solution is to close
   appropriate old issues and create new ones with the same content.
 
+0.6.0 User' timezone support
+----------------------------
+
+- From version 0.6.0 roundup supports displaying of Date data in user' local
+  timezone if he/she has provided timezone information. To make it possible
+  some modification to tracker's schema and HTML templates are required.
+  First you should add string property 'timezone' to user class in dbinit.py
+  like this:
+  
+    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())
+  
+  And second - html interface. Add following lines to
+  $TRACKER_HOME/html/user.item template:
+  
+        <tr>
+         <th>Timezone</th>
+         <td tal:content="structure context/timezone/field">timezone</td>
+        </tr>
+
+  After that all users should be able to provide their timezone information.
+  Timezone should be a positive or negative integer - offset from GMT.
+
+  After providing timezone, roundup will show all dates values, found in web
+  and mail interfaces in local time. It will also accept any Date info in
+  local time, convert and store it in GMT.
+
+  However you are not forced to make these modifications. By default roundup
+  will assume timezone=0 and will work as previous versions did.
 
 Migrating from 0.4.x to 0.5.0
 =============================
index 49c8321815b15ac5bd95553cebed6b35458c0e90..3cb0915741cc94e4a8a8ee7a218c1bc03224ae0f 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: client.py,v 1.73 2003-01-24 06:21:17 richard Exp $
+# $Id: client.py,v 1.74 2003-01-27 16:32:48 kedder Exp $
 
 __doc__ = """
 WWW request handler (also used in the stand-alone server).
@@ -1209,6 +1209,8 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
     props = {}
     keys = form.keys()
     properties = cl.getprops()
+    timezone = db.getUserTimezone()
+
     for key in keys:
         # see if we're performing a special multilink action
         mlaction = 'set'
@@ -1351,7 +1353,7 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
                 # fix the CRLF/CR -> LF stuff
                 value = fixNewlines(value)
             elif isinstance(proptype, hyperdb.Date):
-                value = date.Date(value)
+                value = date.Date(value, offset=timezone)
             elif isinstance(proptype, hyperdb.Interval):
                 value = date.Interval(value)
             elif isinstance(proptype, hyperdb.Boolean):
index 3b846337b242561574aa1b944ed9edabe3ef78b9..948ab30c38d15c22ec0b6a6adc24a9eca87128e9 100644 (file)
@@ -515,6 +515,7 @@ class HTMLItem(HTMLPermissions):
         comments = {}
         history = self._klass.history(self._nodeid)
         history.sort()
+        timezone = self._db.getUserTimezone()
         if direction == 'descending':
             history.reverse()
             for prop_n in self._props.keys():
@@ -530,7 +531,7 @@ class HTMLItem(HTMLPermissions):
                                 self._klass.get(self._nodeid, prop_n, None), current[prop_n])
  
         for id, evt_date, user, action, args in history:
-            date_s = str(evt_date).replace("."," ")
+            date_s = str(evt_date.local(timezone)).replace("."," ")
             arg_s = ''
             if action == 'link' and type(args) == type(()):
                 if len(args) == 3:
@@ -632,10 +633,10 @@ class HTMLItem(HTMLPermissions):
                                     current[k] = old
 
                         elif isinstance(prop, hyperdb.Date) and args[k]:
-                            d = date.Date(args[k])
+                            d = date.Date(args[k]).local(timezone)
                             cell.append('%s: %s'%(k, str(d)))
                             if current.has_key(k):
-                                cell[-1] += ' -> %s'%current[k]
+                                cell[-1] += ' -> %s' % date.Date(current[k]).local(timezone)
                                 current[k] = str(d)
 
                         elif isinstance(prop, hyperdb.Interval) and args[k]:
@@ -918,7 +919,7 @@ class DateHTMLProperty(HTMLProperty):
         '''
         if self._value is None:
             return ''
-        return str(self._value)
+        return str(self._value.local(self._db.getUserTimezone()))
 
     def field(self, size = 30):
         ''' Render a form edit field for the property
@@ -926,7 +927,7 @@ class DateHTMLProperty(HTMLProperty):
         if self._value is None:
             value = ''
         else:
-            value = cgi.escape(str(self._value))
+            value = cgi.escape(str(self._value.local(self._db.getUserTimezone())))
             value = '&quot;'.join(value.split('"'))
         return '<input name="%s" value="%s" size="%s">'%(self._name, value, size)
 
index a12f909c49c20c4b24bf82a2045b89caea7a1a86..962d9b865e379772c49f1c53a9dc84d4512e8a0c 100644 (file)
@@ -73,7 +73,7 @@ are calling the create() method to create a new node). If an auditor raises
 an exception, the original message is bounced back to the sender with the
 explanatory message given in the exception. 
 
-$Id: mailgw.py,v 1.107 2003-01-15 22:17:19 kedder Exp $
+$Id: mailgw.py,v 1.108 2003-01-27 16:32:46 kedder Exp $
 '''
 
 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
@@ -869,7 +869,7 @@ def setPropArrayFromString(self, cl, propString, nodeid = None):
             props[propname] = password.Password(value.strip())
         elif isinstance(proptype, hyperdb.Date):
             try:
-                props[propname] = date.Date(value.strip())
+                props[propname] = date.Date(value.strip()).local(self.db.getUserTimezone())
             except ValueError, message:
                 errors.append('contains an invalid date for %s.'%propname)
         elif isinstance(proptype, hyperdb.Interval):
index 4b3761aebd9772f0f18bf56717e1f5205a047237..162452a901cf13d7ebbdcf29b517404fec5287bf 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: roundupdb.py,v 1.78 2003-01-15 22:17:19 kedder Exp $
+# $Id: roundupdb.py,v 1.79 2003-01-27 16:32:48 kedder Exp $
 
 __doc__ = """
 Extending hyperdb with types specific to issue-tracking.
@@ -55,6 +55,20 @@ class Database:
         that owns this connection to the hyperdatabase."""
         return self.user.lookup(self.journaltag)
 
+    def getUserTimezone(self):
+        """Return user timezone defined in 'timezone' property of user class.
+        If no such property exists return 0
+        """
+        userid = self.getuid()
+        try:
+            timezone = int(self.user.get(userid, 'timezone'))
+        except (KeyError, ValueError):
+            # If there is no class 'user' or current user doesn't have timezone 
+            # property or that property is not numeric assume he/she lives in 
+            # Greenwich :)
+            timezone = 0
+        return timezone
+
 class MessageSendError(RuntimeError):
     pass
 
index cebff2961b284cdc06f6b2fb0a11f3a2370957ec..21b3ca8655d8b88dfcd0c898df1583640d1c14c4 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: dbinit.py,v 1.31 2002-10-10 07:17:39 richard Exp $
+# $Id: dbinit.py,v 1.32 2003-01-27 16:32:50 kedder Exp $
 
 import os
 
@@ -65,7 +65,9 @@ def open(name=None):
                     address=String(),    realname=String(), 
                     phone=String(),      organisation=String(),
                     alternate_addresses=String(),
-                    queries=Multilink('query'), roles=String())
+                    queries=Multilink('query'), roles=String(),
+                    timezone=String())
+)
     user.setkey("username")
 
     # FileClass automatically gets these properties:
index 9e47594c6a66bcd5564b98c13e166b1f8c471cc7..5f6374cc885cd3bc279ce3ea215b180aa23ec933 100644 (file)
@@ -48,6 +48,10 @@ You are not allowed to view this page.
   <th>Organisation</th>
   <td tal:content="structure context/organisation/field">organisation</td>
  </tr>
+ <tr>
+  <th>Timezone</th>
+  <td tal:content="structure context/timezone/field">timezone</td>
+ </tr>
  <tr>
   <th>E-mail address</th>
   <td tal:content="structure context/address/field">address</td>
@@ -95,6 +99,10 @@ You are not allowed to view this page.
   <th>Organisation</th>
   <td tal:content="context/organisation">organisation</td>
  </tr>
+ <tr>
+  <th>Timezone</th>
+  <td tal:content="context/timezone">timezone</td>
+ </tr>
  <tr>
   <th>E-mail address</th>
   <td tal:content="context/address/email">address</td>