changeset 8302:82a26ea1afdf

issue2551376: Fix tracebacks in item templates
author Ralf Schlatterbeck <rsc@runtux.com>
date Wed, 26 Feb 2025 11:24:13 +0100
parents 3ba8078843db
children 45ec660eb7f7
files CHANGES.txt roundup/backends/back_postgresql.py roundup/backends/rdbms_common.py roundup/cgi/templating.py
diffstat 4 files changed, 57 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Wed Feb 19 12:50:07 2025 +0100
+++ b/CHANGES.txt	Wed Feb 26 11:24:13 2025 +0100
@@ -91,7 +91,8 @@
   using -L and -d with roundup-server. (John Rouillard)
 - Allow the specification of a "form" parameter for Date fields to make
   the popup calendar work when the enclosing form has a name different
-  from "itemSynopsis".
+  from "itemSynopsis". (Ralf Schlatterbeck)
+- issue2551376: Fix tracebacks in item templates (Ralf Schlatterbeck)
 
 Features:
 
--- a/roundup/backends/back_postgresql.py	Wed Feb 19 12:50:07 2025 +0100
+++ b/roundup/backends/back_postgresql.py	Wed Feb 26 11:24:13 2025 +0100
@@ -116,7 +116,7 @@
         #
         # Database name is any character sequence not including a " or
         # whitespace. Arguably both are allowed by:
-        # 
+        #
         #  https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
         #
         # with suitable quoting but ... really.
@@ -170,7 +170,7 @@
         #
         # Database name is any character sequence not including a " or
         # whitespace. Arguably both are allowed by:
-        # 
+        #
         #  https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
         #
         # with suitable quoting but ... really.
@@ -560,6 +560,16 @@
             self.cursor.execute('DROP SEQUENCE _%s_ids' % cn)
             self.cursor.execute('CREATE SEQUENCE _%s_ids' % cn)
 
+    def getnode (self, classname, nodeid, fetch_multilinks=True):
+        """ For use of savepoint see 'Class' below """
+        self.sql('savepoint sp')
+        try:
+            getnode = rdbms_common.Database.getnode
+            return getnode(self, classname, nodeid, fetch_multilinks)
+        except psycopg2.errors.DataError as err:
+            self.sql('rollback to savepoint sp')
+            raise hyperdb.HyperdbValueError(str (err).split('\n')[0])
+
 
 class PostgresqlClass:
     order_by_null_values = '(%s is not NULL)'
@@ -567,7 +577,34 @@
 
 
 class Class(PostgresqlClass, rdbms_common.Class):
-    pass
+    """ We re-raise database-specific data errors as HyperdbValueError
+        Note that we re-use the savepoint so that at most one savepoint
+        is used.
+    """
+
+    def filter(self, *args, **kw):
+        self.db.sql('savepoint sp')
+        try:
+            return rdbms_common.Class.filter(self, *args, **kw)
+        except psycopg2.errors.DataError as err:
+            self.db.sql('rollback to savepoint sp')
+            raise hyperdb.HyperdbValueError(str (err).split('\n')[0])
+
+    def filter_iter(self, *args, **kw):
+        self.db.sql('savepoint sp')
+        try:
+            return rdbms_common.Class.filter_iter(self, *args, **kw)
+        except psycopg2.errors.DataError as err:
+            self.db.sql('rollback to savepoint sp')
+            raise hyperdb.HyperdbValueError(str (err).split('\n')[0])
+
+    def is_retired(self, nodeid):
+        self.db.sql('savepoint sp')
+        try:
+            return rdbms_common.Class.is_retired(self, nodeid)
+        except psycopg2.errors.DataError as err:
+            self.db.sql('rollback to savepoint sp')
+            raise hyperdb.HyperdbValueError (str (err).split('\n')[0])
 
 
 class IssueClass(PostgresqlClass, rdbms_common.IssueClass):
--- a/roundup/backends/rdbms_common.py	Wed Feb 19 12:50:07 2025 +0100
+++ b/roundup/backends/rdbms_common.py	Wed Feb 26 11:24:13 2025 +0100
@@ -2248,8 +2248,15 @@
         self.fireReactors('restore', nodeid, None)
 
     def is_retired(self, nodeid):
-        """Return true if the node is rerired
+        """Return true if the node is retired
         """
+        # Do not produce invalid sql, the id must be numeric
+        try:
+            id = int(nodeid)
+        except ValueError:
+            raise hyperdb.HyperdbValueError(_(
+                'class %(cls)s: %(value)r is not an id')
+                % {'cls': self.classname, 'value': nodeid})
         sql = 'select __retired__ from _%s where id=%s' % (self.classname,
                                                            self.db.arg)
         self.db.sql(sql, (nodeid,))
--- a/roundup/cgi/templating.py	Wed Feb 19 12:50:07 2025 +0100
+++ b/roundup/cgi/templating.py	Wed Feb 26 11:24:13 2025 +0100
@@ -1122,7 +1122,7 @@
         try:
             if int(self._nodeid) > 0:
                 value = self._klass.get(self._nodeid, items[0], None)
-        except ValueError:
+        except (IndexError, ValueError):
             value = self._nodeid
         if value is None:
             if isinstance(prop, hyperdb.Multilink):
@@ -2573,9 +2573,9 @@
             if k and num_re.match(self._value):
                 try:
                     value = linkcl.get(self._value, k)
-                except IndexError:
+                except (IndexError, hyperdb.HyperdbValueError) as err:
                     if idparse:
-                        raise
+                        self._client.add_error_message(str(err))
                     value = ''
             else:
                 value = self._value
@@ -2880,7 +2880,10 @@
                 showid = 1
             if not showid:
                 k = linkcl.labelprop(1)
-                value = lookupKeys(linkcl, k, value)
+                try:
+                    value = lookupKeys(linkcl, k, value)
+                except (ValueError, IndexError) as err:
+                    self._client.add_error_message (str(err))
             value = ','.join(value)
             kwargs["value"] = value
 

Roundup Issue Tracker: http://roundup-tracker.org/