Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 5800:1a835db41674
Call cgi.escape only on python 2. Replace with html.escapeif it can be
found.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Tue, 11 Jun 2019 21:29:24 -0400 |
| parents | 97e2125e064c |
| children | 936275dfe1fa |
comparison
equal
deleted
inserted
replaced
| 5799:7ba0ee980fc7 | 5800:1a835db41674 |
|---|---|
| 22 | 22 |
| 23 import base64, cgi, re, os.path, mimetypes, csv, string | 23 import base64, cgi, re, os.path, mimetypes, csv, string |
| 24 import calendar | 24 import calendar |
| 25 import textwrap | 25 import textwrap |
| 26 import time, hashlib | 26 import time, hashlib |
| 27 | |
| 28 try: | |
| 29 from html import escape as html_escape # python 3 | |
| 30 except ImportError: | |
| 31 from cgi import escape as html_escape # python 2 fallback | |
| 27 | 32 |
| 28 from roundup.anypy import urllib_ | 33 from roundup.anypy import urllib_ |
| 29 from roundup import hyperdb, date, support | 34 from roundup import hyperdb, date, support |
| 30 from roundup import i18n | 35 from roundup import i18n |
| 31 from roundup.i18n import _ | 36 from roundup.i18n import _ |
| 428 dic['id'] = dic['name'] | 433 dic['id'] = dic['name'] |
| 429 except KeyError: | 434 except KeyError: |
| 430 pass | 435 pass |
| 431 | 436 |
| 432 def cgi_escape_attrs(**attrs): | 437 def cgi_escape_attrs(**attrs): |
| 433 return ' '.join(['%s="%s"'%(k,cgi.escape(str(v), True)) | 438 return ' '.join(['%s="%s"'%(k,html_escape(str(v), True)) |
| 434 for k,v in sorted(attrs.items())]) | 439 for k,v in sorted(attrs.items())]) |
| 435 | 440 |
| 436 def input_html4(**attrs): | 441 def input_html4(**attrs): |
| 437 """Generate an 'input' (html4) element with given attributes""" | 442 """Generate an 'input' (html4) element with given attributes""" |
| 438 _set_input_default_args(attrs) | 443 _set_input_default_args(attrs) |
| 1042 # there's no labelprop! | 1047 # there's no labelprop! |
| 1043 try: | 1048 try: |
| 1044 if labelprop is not None and \ | 1049 if labelprop is not None and \ |
| 1045 labelprop != 'id': | 1050 labelprop != 'id': |
| 1046 label = linkcl.get(linkid, labelprop) | 1051 label = linkcl.get(linkid, labelprop) |
| 1047 label = cgi.escape(label) | 1052 label = html_escape(label) |
| 1048 except IndexError: | 1053 except IndexError: |
| 1049 comments['no_link'] = self._( | 1054 comments['no_link'] = self._( |
| 1050 "<strike>The linked node" | 1055 "<strike>The linked node" |
| 1051 " no longer exists</strike>") | 1056 " no longer exists</strike>") |
| 1052 subml.append('<strike>%s</strike>'%label) | 1057 subml.append('<strike>%s</strike>'%label) |
| 1067 # if we have a label property, try to use it | 1072 # if we have a label property, try to use it |
| 1068 # TODO: test for node existence even when | 1073 # TODO: test for node existence even when |
| 1069 # there's no labelprop! | 1074 # there's no labelprop! |
| 1070 if labelprop is not None and labelprop != 'id': | 1075 if labelprop is not None and labelprop != 'id': |
| 1071 try: | 1076 try: |
| 1072 label = cgi.escape(linkcl.get(args[k], | 1077 label = html_escape(linkcl.get(args[k], |
| 1073 labelprop)) | 1078 labelprop)) |
| 1074 except IndexError: | 1079 except IndexError: |
| 1075 comments['no_link'] = self._( | 1080 comments['no_link'] = self._( |
| 1076 "<strike>The linked node" | 1081 "<strike>The linked node" |
| 1077 " no longer exists</strike>") | 1082 " no longer exists</strike>") |
| 1107 if k in current and current[k] is not None: | 1112 if k in current and current[k] is not None: |
| 1108 cell[-1] += ' -> %s'%current[k] | 1113 cell[-1] += ' -> %s'%current[k] |
| 1109 current[k] = val | 1114 current[k] = val |
| 1110 | 1115 |
| 1111 elif isinstance(prop, hyperdb.String) and args[k]: | 1116 elif isinstance(prop, hyperdb.String) and args[k]: |
| 1112 val = cgi.escape(args[k]) | 1117 val = html_escape(args[k]) |
| 1113 cell.append('%s: %s'%(self._(k), val)) | 1118 cell.append('%s: %s'%(self._(k), val)) |
| 1114 if k in current and current[k] is not None: | 1119 if k in current and current[k] is not None: |
| 1115 cell[-1] += ' -> %s'%current[k] | 1120 cell[-1] += ' -> %s'%current[k] |
| 1116 current[k] = val | 1121 current[k] = val |
| 1117 | 1122 |
| 1153 # if the user's an itemid, figure the username (older journals | 1158 # if the user's an itemid, figure the username (older journals |
| 1154 # have the username) | 1159 # have the username) |
| 1155 if dre.match(user): | 1160 if dre.match(user): |
| 1156 user = self._db.user.get(user, 'username') | 1161 user = self._db.user.get(user, 'username') |
| 1157 l.append('<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>'%( | 1162 l.append('<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>'%( |
| 1158 date_s, cgi.escape(user), self._(action), arg_s)) | 1163 date_s, html_escape(user), self._(action), arg_s)) |
| 1159 if comments: | 1164 if comments: |
| 1160 l.append(self._( | 1165 l.append(self._( |
| 1161 '<tr><td colspan=4><strong>Note:</strong></td></tr>')) | 1166 '<tr><td colspan=4><strong>Note:</strong></td></tr>')) |
| 1162 for entry in comments.values(): | 1167 for entry in comments.values(): |
| 1163 l.append('<tr><td colspan=4>%s</td></tr>'%entry) | 1168 l.append('<tr><td colspan=4>%s</td></tr>'%entry) |
| 1488 return self._('[hidden]') | 1493 return self._('[hidden]') |
| 1489 | 1494 |
| 1490 if self._value is None: | 1495 if self._value is None: |
| 1491 return '' | 1496 return '' |
| 1492 if escape: | 1497 if escape: |
| 1493 s = cgi.escape(str(self._value)) | 1498 s = html_escape(str(self._value)) |
| 1494 else: | 1499 else: |
| 1495 s = str(self._value) | 1500 s = str(self._value) |
| 1496 if hyperlink: | 1501 if hyperlink: |
| 1497 # no, we *must* escape this text | 1502 # no, we *must* escape this text |
| 1498 if not escape: | 1503 if not escape: |
| 1499 s = cgi.escape(s) | 1504 s = html_escape(s) |
| 1500 s = self.hyper_re.sub(self._hyper_repl, s) | 1505 s = self.hyper_re.sub(self._hyper_repl, s) |
| 1501 return s | 1506 return s |
| 1502 | 1507 |
| 1503 def wrapped(self, escape=1, hyperlink=1): | 1508 def wrapped(self, escape=1, hyperlink=1): |
| 1504 """Render a "wrapped" representation of the property. | 1509 """Render a "wrapped" representation of the property. |
| 1518 | 1523 |
| 1519 if self._value is None: | 1524 if self._value is None: |
| 1520 return '' | 1525 return '' |
| 1521 s = '\n'.join(textwrap.wrap(str(self._value), 80)) | 1526 s = '\n'.join(textwrap.wrap(str(self._value), 80)) |
| 1522 if escape: | 1527 if escape: |
| 1523 s = cgi.escape(s) | 1528 s = html_escape(s) |
| 1524 if hyperlink: | 1529 if hyperlink: |
| 1525 # no, we *must* escape this text | 1530 # no, we *must* escape this text |
| 1526 if not escape: | 1531 if not escape: |
| 1527 s = cgi.escape(s) | 1532 s = html_escape(s) |
| 1528 s = self.hyper_re.sub(self._hyper_repl, s) | 1533 s = self.hyper_re.sub(self._hyper_repl, s) |
| 1529 return s | 1534 return s |
| 1530 | 1535 |
| 1531 def stext(self, escape=0, hyperlink=1): | 1536 def stext(self, escape=0, hyperlink=1): |
| 1532 """ Render the value of the property as StructuredText. | 1537 """ Render the value of the property as StructuredText. |
| 1582 return '<pre>%s</pre>'%self.plain() | 1587 return '<pre>%s</pre>'%self.plain() |
| 1583 | 1588 |
| 1584 if self._value is None: | 1589 if self._value is None: |
| 1585 value = '' | 1590 value = '' |
| 1586 else: | 1591 else: |
| 1587 value = cgi.escape(str(self._value)) | 1592 value = html_escape(str(self._value)) |
| 1588 | 1593 |
| 1589 value = '"'.join(value.split('"')) | 1594 value = '"'.join(value.split('"')) |
| 1590 name = self._formname | 1595 name = self._formname |
| 1591 passthrough_args = cgi_escape_attrs(**kwargs) | 1596 passthrough_args = cgi_escape_attrs(**kwargs) |
| 1592 return ('<textarea %(passthrough_args)s name="%(name)s" id="%(name)s"' | 1597 return ('<textarea %(passthrough_args)s name="%(name)s" id="%(name)s"' |
| 1610 name = name.replace('.', ' ') | 1615 name = name.replace('.', ' ') |
| 1611 value = '%s at %s ...'%(name, domain) | 1616 value = '%s at %s ...'%(name, domain) |
| 1612 else: | 1617 else: |
| 1613 value = value.replace('.', ' ') | 1618 value = value.replace('.', ' ') |
| 1614 if escape: | 1619 if escape: |
| 1615 value = cgi.escape(value) | 1620 value = html_escape(value) |
| 1616 return value | 1621 return value |
| 1617 | 1622 |
| 1618 class PasswordHTMLProperty(HTMLProperty): | 1623 class PasswordHTMLProperty(HTMLProperty): |
| 1619 def plain(self, escape=0): | 1624 def plain(self, escape=0): |
| 1620 """ Render a "plain" representation of the property | 1625 """ Render a "plain" representation of the property |
| 1627 try: | 1632 try: |
| 1628 value = self._value.dummystr() | 1633 value = self._value.dummystr() |
| 1629 except AttributeError: | 1634 except AttributeError: |
| 1630 value = self._('[hidden]') | 1635 value = self._('[hidden]') |
| 1631 if escape: | 1636 if escape: |
| 1632 value = cgi.escape(value) | 1637 value = html_escape(value) |
| 1633 return value | 1638 return value |
| 1634 | 1639 |
| 1635 def field(self, size=30, **kwargs): | 1640 def field(self, size=30, **kwargs): |
| 1636 """ Render a form edit field for the property. | 1641 """ Render a form edit field for the property. |
| 1637 | 1642 |
| 2089 except IndexError: | 2094 except IndexError: |
| 2090 value = self._value | 2095 value = self._value |
| 2091 else : | 2096 else : |
| 2092 value = self._value | 2097 value = self._value |
| 2093 if escape: | 2098 if escape: |
| 2094 value = cgi.escape(value) | 2099 value = html_escape(value) |
| 2095 return value | 2100 return value |
| 2096 | 2101 |
| 2097 def field(self, showid=0, size=None, **kwargs): | 2102 def field(self, showid=0, size=None, **kwargs): |
| 2098 """ Render a form edit field for the property | 2103 """ Render a form edit field for the property |
| 2099 | 2104 |
| 2241 | 2246 |
| 2242 # and generate | 2247 # and generate |
| 2243 tr = str | 2248 tr = str |
| 2244 if translate: | 2249 if translate: |
| 2245 tr = self._ | 2250 tr = self._ |
| 2246 lab = cgi.escape(tr(lab)) | 2251 lab = html_escape(tr(lab)) |
| 2247 l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab)) | 2252 l.append('<option %svalue="%s">%s</option>'%(s, optionid, lab)) |
| 2248 l.append('</select>') | 2253 l.append('</select>') |
| 2249 return '\n'.join(l) | 2254 return '\n'.join(l) |
| 2250 # def checklist(self, ...) | 2255 # def checklist(self, ...) |
| 2251 | 2256 |
| 2340 else: | 2345 else: |
| 2341 label = v | 2346 label = v |
| 2342 labels.append(label) | 2347 labels.append(label) |
| 2343 value = ', '.join(labels) | 2348 value = ', '.join(labels) |
| 2344 if escape: | 2349 if escape: |
| 2345 value = cgi.escape(value) | 2350 value = html_escape(value) |
| 2346 return value | 2351 return value |
| 2347 | 2352 |
| 2348 def field(self, size=30, showid=0, **kwargs): | 2353 def field(self, size=30, showid=0, **kwargs): |
| 2349 """ Render a form edit field for the property | 2354 """ Render a form edit field for the property |
| 2350 | 2355 |
| 2477 | 2482 |
| 2478 # and generate | 2483 # and generate |
| 2479 tr = str | 2484 tr = str |
| 2480 if translate: | 2485 if translate: |
| 2481 tr = self._ | 2486 tr = self._ |
| 2482 lab = cgi.escape(tr(lab)) | 2487 lab = html_escape(tr(lab)) |
| 2483 l.append('<option %svalue="%s">%s</option>'%(s, optionid, | 2488 l.append('<option %svalue="%s">%s</option>'%(s, optionid, |
| 2484 lab)) | 2489 lab)) |
| 2485 l.append('</select>') | 2490 l.append('</select>') |
| 2486 return '\n'.join(l) | 2491 return '\n'.join(l) |
| 2487 | 2492 |
| 3080 """URL-quote the supplied text.""" | 3085 """URL-quote the supplied text.""" |
| 3081 return urllib_.quote(url) | 3086 return urllib_.quote(url) |
| 3082 | 3087 |
| 3083 def html_quote(self, html): | 3088 def html_quote(self, html): |
| 3084 """HTML-quote the supplied text.""" | 3089 """HTML-quote the supplied text.""" |
| 3085 return cgi.escape(html) | 3090 return html_escape(html) |
| 3086 | 3091 |
| 3087 def __getattr__(self, name): | 3092 def __getattr__(self, name): |
| 3088 """Try the tracker's templating_utils.""" | 3093 """Try the tracker's templating_utils.""" |
| 3089 if not hasattr(self.client.instance, 'templating_utils'): | 3094 if not hasattr(self.client.instance, 'templating_utils'): |
| 3090 # backwards-compatibility | 3095 # backwards-compatibility |
