[-]
[+]
|
Changed |
trac.spec
|
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/ChangeLog
^
|
@@ -1,3 +1,42 @@
+Trac 0.11.2.1 (November 17, 2008)
+http://svn.edgewall.org/repos/trac/tags/trac-0.11.2.1
+
+ Trac 0.11.2.1 fixes a Python 2.3 incompatibility introduced in Trac 0.11.2.
+ Python 2.4+ users already running Trac 0.11.2 do not need to upgrade.
+
+Trac 0.11.2 (November 8, 2008)
+http://svn.edgewall.org/repos/trac/tags/trac-0.11.2
+
+ Trac 0.11.2 contains two security fixes and a couple of bug fixes.
+ The following list contains only a few highlights:
+
+Bug fixes:
+
+ * Fixes potential DOS vulnerability with certain wiki markup. Reported by
+ Matt Murphy.
+ * Improved HTML sanitizer filter to detect possible phishing attempts.
+ Reported by Simon Willison.
+ * MySQL db backend improvement (reconnect after idle timeout #4465)
+ * TicketQuery speed improvements (#6436)
+ * Fixes for RSS feeds (timeline entries no longer truncated #7316, no longer
+ download some feeds under Firefox #3899)
+ * Search now works for custom fields (#2530)
+ * Same order for ticket fields for new and existing tickets (#7018)
+ * Enforce fine-grained permission for "quickjump" search results (#7655)
+ * E-mail obfuscation was not done in a few remaining places (#7688, #6532)
+ * Uninstall of plugins from WebAdmin was not working - feature disabled
+ for now
+ * More robust pagination of results for reports and custom queries (#7424,
+ #7544)
+ * Support for newer version of pygments (#7622)
+ * Documentation updated (#7603, #7205, #7318)
+
+Minor improvements:
+
+ * Better support for Wiki page hierarchy (show path #2780, link to
+ parent #2150)
+ * Custom query allow to search in description and other text fields (#4824)
+
Trac 0.11.1 (August 6, 2008)
http://svn.edgewall.org/repos/trac/tags/trac-0.11.1
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/PKG-INFO
^
|
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: Trac
-Version: 0.11.1
+Version: 0.11.2.1
Summary: Integrated SCM, wiki, issue tracker and project environment
Home-page: http://trac.edgewall.org/
Author: Edgewall Software
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/RELEASE
^
|
@@ -1,21 +1,10 @@
-Release Notes for Trac 0.11.1 Genshi Release
-============================================
-August 6, 2008
+Release Notes for Trac 0.11.2.1 Genshi Release
+==============================================
+November 17, 2008
-Trac 0.11.1 is a maintenance release and contains a number of bug fixes
-and minor enhancements. The following list contains only a few highlights:
+Trac 0.11.2.1 fixes a Python 2.3 incompatibility introduced in Trac 0.11.2.
+Python 2.4+ users already running Trac 0.11.2 do not need to upgrade.
- * Improved DB connection handling (new connection pool)
- * Better MySQL backend unicode support. "utf8" and "utf8_bin" is the
- recommended database charset and collation settings.
- * Fixes intermittent "constraint violation" and "invalid form token"
- error messages.
- * Fixes roadmap layout glitch in Firefox 3.
- * Safer default umask value for tracd (can be set using --umask option)
- * Better default PYTHON_EGG_CACHE value.
-
-The complete list of closed tickets can be found here:
-http://trac.edgewall.org/query?status=closed&milestone=0.11.1
Highlights in 0.11
------------------
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/Trac.egg-info/PKG-INFO
^
|
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: Trac
-Version: 0.11.1
+Version: 0.11.2.1
Summary: Integrated SCM, wiki, issue tracker and project environment
Home-page: http://trac.edgewall.org/
Author: Edgewall Software
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/Trac.egg-info/SOURCES.txt
^
|
@@ -230,6 +230,10 @@
trac/tests/functional/testcases.py
trac/tests/functional/testenv.py
trac/tests/functional/tester.py
+trac/tests/functional/xhtml-lat1.ent
+trac/tests/functional/xhtml-special.ent
+trac/tests/functional/xhtml-symbol.ent
+trac/tests/functional/xhtml1-strict.dtd
trac/ticket/__init__.py
trac/ticket/admin.py
trac/ticket/api.py
@@ -392,6 +396,7 @@
trac/wiki/default-pages/TracLinks
trac/wiki/default-pages/TracLogging
trac/wiki/default-pages/TracModPython
+trac/wiki/default-pages/TracModWSGI
trac/wiki/default-pages/TracNavigation
trac/wiki/default-pages/TracNotification
trac/wiki/default-pages/TracPermissions
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/contrib/checkwiki.py
^
|
@@ -38,6 +38,7 @@
"TracLinks",
"TracLogging",
"TracModPython",
+ "TracModWSGI",
"TracNavigation",
"TracNotification",
"TracPermissions",
@@ -121,7 +122,7 @@
opts, args = getopt.getopt(sys.argv[1:], "d")
except getopt.GetoptError:
# print help information and exit:
- print "%s [-d]" % sys.argv[0]
+ print "%s [-d] [PAGE ...]" % sys.argv[0]
print "\t-d -- Download pages from the main project wiki."
sys.exit()
get_page = get_page_from_file
@@ -129,7 +130,7 @@
if o == '-d':
get_page = get_page_from_web
data = {}
- for p in wiki_pages:
+ for p in args or wiki_pages:
data[p] = get_page (p)
check_links(data)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/contrib/trac-post-commit-hook
^
|
@@ -32,6 +32,7 @@
#
# REPOS="$1"
# REV="$2"
+# TRAC_ENV="/path/to/tracenv"
#
# /usr/bin/python /usr/local/src/trac/contrib/trac-post-commit-hook \
# -p "$TRAC_ENV" -r "$REV"
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/HelloWorld.py
^
|
@@ -1,7 +1,7 @@
"""Example macro."""
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/HelloWorld.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/HelloWorld.py $"
#
# The following shows the code for macro, old-style.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/Timestamp.py
^
|
@@ -1,7 +1,7 @@
"""Inserts the current time (in seconds) into the wiki page."""
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/Timestamp.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/Timestamp.py $"
#
# The following shows the code for macro, old-style.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/permissions/authz_policy.py
^
|
@@ -15,7 +15,7 @@
# Author: Alec Thomas <alec@swapoff.org>
revision = "$Rev: 6904 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/permissions/authz_policy.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/permissions/authz_policy.py $"
"""Permission policy enforcement through an authz-like configuration file.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/permissions/public_wiki_policy.py
^
|
@@ -5,7 +5,7 @@
from trac.perm import IPermissionPolicy
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/permissions/public_wiki_policy.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/permissions/public_wiki_policy.py $"
class PublicWikiPolicy(Component):
"""Allow public access to some wiki pages.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/permissions/vulnerability_tickets.py
^
|
@@ -2,7 +2,7 @@
from trac.perm import IPermissionPolicy, IPermissionRequestor
revision = "$Rev: 6669 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/permissions/vulnerability_tickets.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/permissions/vulnerability_tickets.py $"
class SecurityTicketsPolicy(Component):
"""Prevent public access to security sensitive tickets.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/revision_links.py
^
|
@@ -9,7 +9,7 @@
from trac.wiki.api import IWikiSyntaxProvider
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/revision_links.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/revision_links.py $"
class RevisionLinks(Component):
"""Adds a few more ways to refer to changesets."""
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/ticket_clone.py
^
|
@@ -5,7 +5,7 @@
from genshi.filters import Transformer
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/ticket_clone.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/ticket_clone.py $"
class SimpleTicketCloneButton(Component):
"""Add a 'Clone' button to the ticket box.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/workflow/CodeReview.py
^
|
@@ -8,7 +8,7 @@
from trac.util.compat import set
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/workflow/CodeReview.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/workflow/CodeReview.py $"
class CodeReviewActionController(Component):
"""Support for simple code reviews.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/workflow/DeleteTicket.py
^
|
@@ -5,7 +5,7 @@
from trac.perm import IPermissionRequestor
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/workflow/DeleteTicket.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/workflow/DeleteTicket.py $"
class DeleteTicketActionController(Component):
"""Provides the admin with a way to delete a ticket.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/workflow/StatusFixer.py
^
|
@@ -5,7 +5,7 @@
from trac.perm import IPermissionRequestor
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/workflow/StatusFixer.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/workflow/StatusFixer.py $"
class StatusFixerActionController(Component):
"""Provides the admin with a way to correct a ticket's status.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/sample-plugins/workflow/VoteOperation.py
^
|
@@ -7,7 +7,7 @@
#from trac.perm import IPermissionRequestor # (TODO)
revision = "$Rev: 6326 $"
-url = "$URL: http://svn.edgewall.org/repos/trac/branches/0.11-stable/sample-plugins/workflow/VoteOperation.py $"
+url = "$URL: http://svn.edgewall.com/repos/trac/branches/0.11-stable/sample-plugins/workflow/VoteOperation.py $"
class VoteOperation(Component):
"""Provides a simplistic vote feature.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/setup.py
^
|
@@ -16,7 +16,7 @@
setup(
name = 'Trac',
- version = '0.11.1',
+ version = '0.11.2.1',
description = 'Integrated SCM, wiki, issue tracker and project environment',
long_description = """
Trac is a minimalistic web-based software project management and bug/issue
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/about.py
^
|
@@ -50,7 +50,7 @@
# IRequestHandler methods
def match_request(self, req):
- return re.match(r'/about(?:_trac)?(?:/.*)?$', req.path_info)
+ return re.match(r'/about(?:_trac)?(?:/.+)?$', req.path_info)
def process_request(self, req):
data = {}
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/admin/console.py
^
|
@@ -917,7 +917,6 @@
'Move a resolution value up or down in the list')]
def complete_resolution (self, text, line, begidx, endidx):
- print begidx
if begidx == 18:
comp = self.get_enum_list ('resolution')
elif begidx < 17:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/admin/templates/admin_milestones.html
^
|
@@ -96,10 +96,10 @@
<table class="listing" id="millist">
<thead>
<tr><th class="sel"> </th>
- <th>Name</th><th>Due</th><th>Completed</th><th>Default</th>
+ <th>Name</th><th>Due</th><th>Completed</th><th>Default</th><th>Tickets</th>
</tr>
</thead>
- <tbody><tr py:for="milestone in milestones">
+ <tbody><tr py:for="(milestone, ticket_count) in milestones">
<td>
<input type="checkbox" name="sel" value="$milestone.name" />
</td>
@@ -116,6 +116,7 @@
<input type="radio" name="default" value="$milestone.name"
checked="${milestone.name==default or None}" />
</td>
+ <td class="num">${ticket_count}</td>
</tr></tbody>
</table>
<div class="buttons">
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/admin/templates/admin_plugins.html
^
|
@@ -43,12 +43,13 @@
<form py:for="idx, plugin in enumerate(plugins)" method="post" action="">
<div class="plugin">
<h3>${plugin.name} ${plugin.version}</h3>
+ <!--! FIXME: Plugin uninstall disabled as it is unreliable (#3545)
<div class="uninstall buttons">
<input type="hidden" name="plugin_filename"
value="${plugin.plugin_filename}" />
<input type="submit" name="uninstall" value="Uninstall"
disabled="${plugin.readonly or None}" />
- </div>
+ </div> -->
<py:if test="plugin.info">
<p class="summary">${plugin.info.get('summary')}</p>
<dl py:if="'home_page' in plugin.info or
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/admin/web_ui.py
^
|
@@ -69,7 +69,7 @@
# IRequestHandler methods
def match_request(self, req):
- match = re.match('/admin(?:/([^/]+))?(?:/([^/]+))?(?:/(.*)$)?',
+ match = re.match('/admin(?:/([^/]+)(?:/([^/]+)(?:/(.+))?)?)?$',
req.path_info)
if match:
req.args['cat_id'] = match.group(1)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/attachment.py
^
|
@@ -42,7 +42,7 @@
INavigationContributor
from trac.web.href import Href
from trac.wiki.api import IWikiSyntaxProvider
-from trac.wiki.formatter import format_to_oneliner
+from trac.wiki.formatter import format_to
class InvalidAttachment(TracError):
@@ -345,7 +345,7 @@
# IRequestHandler methods
def match_request(self, req):
- match = re.match(r'^/(raw-)?attachment/([^/]+)(?:[/:](.*))?$',
+ match = re.match(r'/(raw-)?attachment/([^/]+)(?:/(.*))?$',
req.path_info)
if match:
raw, realm, path = match.groups()
@@ -353,7 +353,7 @@
req.args['format'] = 'raw'
req.args['realm'] = realm
if path:
- req.args['path'] = path.replace(':', '/')
+ req.args['path'] = path
return True
def process_request(self, req):
@@ -474,8 +474,7 @@
return tag(tag.em(os.path.basename(attachment.id)),
_(" attached to "), tag.em(name, title=title))
elif field == 'description':
- return format_to_oneliner(self.env, context(attachment.parent),
- descr)
+ return format_to(self.env, None, context(attachment.parent), descr)
def get_search_results(self, req, resource_realm, terms):
"""Return a search result generator suitable for ISearchSource.
@@ -721,7 +720,7 @@
ids[2])
else: # local attachment: TracLinks (filename)
attachment = formatter.resource.child('attachment', link)
- if attachment:
+ if attachment and 'ATTACHMENT_VIEW' in formatter.perm(attachment):
try:
model = Attachment(self.env, attachment)
format = None
@@ -744,7 +743,7 @@
# if attachment.exists:
#
# (related to #4130)
- return tag.a(label, class_='missing attachment', rel='nofollow')
+ return tag.a(label, class_='missing attachment')
class LegacyAttachmentPolicy(Component):
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/db/mysql_backend.py
^
|
@@ -196,4 +196,3 @@
def cursor(self):
return MySQLUnicodeCursor(self.cnx)
-
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/db/pool.py
^
|
@@ -23,6 +23,7 @@
import time
from trac.db.util import ConnectionWrapper
+from trac.util.translation import _
class TimeoutError(Exception):
@@ -94,6 +95,13 @@
self._pool_key.pop(idx)
self._pool_time.pop(idx)
cnx = self._pool.pop(idx)
+ # If possible, verify that the pooled connection is
+ # still available and working.
+ if hasattr(cnx, 'ping'):
+ try:
+ cnx.ping()
+ except:
+ continue
# Third best option: Create a new connection
elif len(self._active) + len(self._pool) < self._maxsize:
cnx = connector.get_connection(**kwargs)
@@ -124,13 +132,13 @@
try:
assert (tid, key) in self._active
cnx, num = self._active[(tid, key)]
- if num == 1 and cnx.poolable and try_rollback(cnx):
- del self._active[(tid, key)]
- self._pool.append(cnx)
- self._pool_key.append(key)
- self._pool_time.append(time.time())
- elif num == 1:
+ if num == 1:
del self._active[(tid, key)]
+ self._available.notify()
+ if cnx.poolable and try_rollback(cnx):
+ self._pool.append(cnx)
+ self._pool_key.append(key)
+ self._pool_time.append(time.time())
else:
self._active[(tid, key)] = (cnx, num - 1)
finally:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/env.py
^
|
@@ -100,6 +100,13 @@
limitation that this environment will only be usable when accessible
from that URL, as redirects are frequently used. ''(since 0.10.5)''""")
+ secure_cookies = BoolOption('trac', 'secure_cookies', False,
+ """Restrict cookies to HTTPS connections.
+
+ When true, set the `secure` flag on all cookies so that they are
+ only sent to the server on HTTPS connections. Use this if your Trac
+ instance is only accessible through HTTPS. (''since 0.11.2'')""")
+
project_name = Option('project', 'name', 'My Project',
"""Name of the project.""")
@@ -547,6 +554,7 @@
'Trac requires this variable to point to a valid '
'Trac environment.'))
+ env_path = os.path.normcase(os.path.normpath(env_path))
if use_cache:
env_cache_lock.acquire()
try:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/htdocs/css/admin.css
^
|
@@ -33,6 +33,7 @@
table.listing { clear: none; width: 64% }
table.listing .sel, table.listing .default { text-align: center; width: 1% }
+table.listing .num { text-align: right; width: 1% }
/* Plugins panel */
form#addplug { width: 35% }
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/htdocs/css/report.css
^
|
@@ -50,8 +50,6 @@
/* Styles for the report list and the report results table
(extends the styles for "table.listing") */
.reports td.title { width: 100% }
-.reports tbody td :link, .reports tbody td :visited,
-.tickets tbody td :link, .tickets tbody td :visited { display: block }
.tickets { border-bottom: none }
.tickets thead th { text-transform: capitalize; white-space: nowrap; }
.tickets tbody td, .reports tbody td { padding: .1em .5em !important }
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/htdocs/css/trac.css
^
|
@@ -302,12 +302,10 @@
.wikipage { padding-left: 18px }
.wikipage h1, .wikipage h2, .wikipage h3 { margin-left: -18px }
-a.missing:link, a.missing:visited, span.missing { color: #998 }
-a.missing:link, a.missing:visited { background: #fafaf0 }
+a.missing:link, a.missing:visited, a.missing, span.missing,
+a.forbidden, span.forbidden { color: #998 }
a.missing:hover { color: #000 }
-a.closed:link, a.closed:visited { text-decoration: line-through }
-span.closed { text-decoration: line-through }
-span.forbidden, a.forbidden { background: #fafaf0; color: #998; }
+a.closed:link, a.closed:visited, span.closed { text-decoration: line-through }
/* User-selectable styles for blocks */
.important {
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/htdocs/css/wiki.css
^
|
@@ -1,5 +1,11 @@
@import url(code.css);
+/* Styles for the path of hierarchical pages */
+p.path { margin: 0; padding: 0 0 .5em; font-size: .75em }
+p.path :link, p.path :visited { margin: 0 .2em }
+p.path .sep { color: #666; padding: 0 .1em }
+p.path .pathentry { float: left }
+
/* Styles for the page editing form */
#edit #rows { float: right; font-size: 80% }
#edit #rows select { font-size: 90% }
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/htdocs/js/query.js
^
|
@@ -225,7 +225,7 @@
td.className = "filter";
if (property.type == "select") {
var element = createSelect(propertyName, property.options, true);
- } else if (property.type == "text") {
+ } else if ((property.type == "text") || (property.type == "textarea")) {
var element = document.createElement("input");
element.type = "text";
element.name = propertyName;
|
|
Changed |
Trac-0.11.2.1.tar.gz/trac/htdocs/topbar_gradient2.png
^
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/mimeview/api.py
^
|
@@ -124,6 +124,7 @@
self.resource = resource
self.href = href
self.perm = resource and perm and perm(resource) or perm
+ self._hints = None
def from_request(cls, req, resource=None, id=False, version=False,
absurls=False):
@@ -171,14 +172,15 @@
context = context.parent
return '<%s %s>' % (type(self).__name__, ' - '.join(reversed(path)))
- def __call__(self, resource, id=False, version=False):
+ def __call__(self, resource=None, id=False, version=False):
"""Create a nested rendering context.
`self` will be the parent for the new nested context.
:param resource: either a `Resource` object or the realm string for a
resource specification to be associated to the new
- context
+ context. If `None`, the resource will be the same
+ as the resource of the parent context.
:param id: the identifier part of the resource specification
:param version: the version of the resource specification
:return: the new context object
@@ -190,8 +192,13 @@
True
>>> context(ticket1).resource is ticket1
True
+ >>> context(ticket1)().resource is ticket1
+ True
"""
- resource = Resource(resource, id=id, version=version)
+ if resource:
+ resource = Resource(resource, id=id, version=version)
+ else:
+ resource = self.resource
context = Context(resource, href=self.href, perm=self.perm)
context.parent = self
@@ -222,6 +229,79 @@
return True
context = context.parent
+ # Rendering hints
+ #
+ # A rendering hint is a key/value pairs that can influence renderers,
+ # wiki formatters and processors in the way they produce their output.
+ # The keys are strings, but the values could be anything.
+ #
+ # In nested contexts, the hints are inherited from their parent context,
+ # unless overriden locally.
+
+ def set_hints(self, **keyvalues):
+ """Set rendering hints for this rendering context.
+
+ >>> ctx = Context('timeline')
+ >>> ctx.set_hints(wiki_flavor='oneliner', shorten_lines=True)
+ >>> t_ctx = ctx('ticket', 1)
+ >>> t_ctx.set_hints(wiki_flavor='html', preserve_newlines=True)
+ >>> (t_ctx.get_hint('wiki_flavor'), t_ctx.get_hint('shorten_lines'), \
+ t_ctx.get_hint('preserve_newlines'))
+ ('html', True, True)
+ >>> (ctx.get_hint('wiki_flavor'), ctx.get_hint('shorten_lines'), \
+ ctx.get_hint('preserve_newlines'))
+ ('oneliner', True, None)
+ """
+ if self._hints is None:
+ self._hints = {}
+ hints = self._parent_hints()
+ if hints is not None:
+ self._hints.update(hints)
+ self._hints.update(keyvalues)
+
+ def get_hint(self, hint, default=None):
+ """Retrieve a rendering hint from this context or an ancestor context.
+
+ >>> ctx = Context('timeline')
+ >>> ctx.set_hints(wiki_flavor='oneliner')
+ >>> t_ctx = ctx('ticket', 1)
+ >>> t_ctx.get_hint('wiki_flavor')
+ 'oneliner'
+ >>> t_ctx.get_hint('preserve_newlines', True)
+ True
+ """
+ hints = self._hints
+ if hints is None:
+ hints = self._parent_hints()
+ if hints is None:
+ return default
+ return hints.get(hint, default)
+
+ def has_hint(self, hint):
+ """Test whether a rendering hint is defined in this context or in some
+ ancestor context.
+
+ >>> ctx = Context('timeline')
+ >>> ctx.set_hints(wiki_flavor='oneliner')
+ >>> t_ctx = ctx('ticket', 1)
+ >>> t_ctx.has_hint('wiki_flavor')
+ True
+ >>> t_ctx.has_hint('preserve_newlines')
+ False
+ """
+ hints = self._hints
+ if hints is None:
+ hints = self._parent_hints()
+ if hints is None:
+ return False
+ return hint in hints
+
+ def _parent_hints(self):
+ p = self.parent
+ while p and p._hints is None:
+ p = p.parent
+ return p and p._hints
+
# Some common MIME types and their associated keywords and/or file extensions
@@ -834,7 +914,8 @@
content, selector)
req.send_response(200)
req.send_header('Content-Type', output_type)
- req.send_header('Content-Disposition', 'filename=%s.%s' %
+ if filename:
+ req.send_header('Content-Disposition', 'filename=%s.%s' %
(filename, ext))
req.end_headers()
req.write(content)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/mimeview/pygments.py
^
|
@@ -177,9 +177,10 @@
def _init_types(self):
self._types = {}
- for _, aliases, _, mimetypes in get_all_lexers():
+ for lexname, aliases, _, mimetypes in get_all_lexers():
+ name = aliases and aliases[0] or lexname
for mimetype in mimetypes:
- self._types[mimetype] = (aliases[0], self.QUALITY_RATIO)
+ self._types[mimetype] = (name, self.QUALITY_RATIO)
self._types.update(
Mimeview(self.env).configured_modes_mapping('pygments')
)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/mimeview/tests/pygments.py
^
|
@@ -93,14 +93,24 @@
def test_newline_content(self):
"""
- stripnl defaults to True in Pygments!
+ The behavior of Pygments changed post-Pygments 0.11.1, and now
+ contains all four newlines. In Pygments 0.11.1 and prior, it only
+ has three since stripnl defaults to True.
- Even without it set, files still end up one line shorter.
+ See http://trac.edgewall.org/ticket/7705.
"""
+ from pkg_resources import parse_version, get_distribution
+
result = self.pygments.render(self.context, 'text/x-python', '\n\n\n\n')
self.assertTrue(result)
t = "".join([r[1] for r in result if r[0] is TEXT])
- self.assertEqual("\n\n\n", t)
+
+ if parse_version(pygments.__version__) > parse_version('0.11.1') \
+ or pygments.__version__ == '0.11.1' and 'dev' in \
+ get_distribution('Pygments').version:
+ self.assertEqual("\n\n\n\n", t)
+ else:
+ self.assertEqual("\n\n\n", t)
def test_empty_content(self):
"""
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/prefs/web_ui.py
^
|
@@ -50,7 +50,7 @@
# IRequestHandler methods
def match_request(self, req):
- match = re.match('/prefs(?:/([^/]+))?', req.path_info)
+ match = re.match('/prefs(?:/([^/]+))?$', req.path_info)
if match:
req.args['panel_id'] = match.group(1)
return True
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/search/web_ui.py
^
|
@@ -65,7 +65,7 @@
# IRequestHandler methods
def match_request(self, req):
- return re.match(r'/search/?', req.path_info) is not None
+ return re.match(r'/search(?:/opensearch)?$', req.path_info) is not None
def process_request(self, req):
req.perm.assert_permission('SEARCH_VIEW')
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/templates/diff_div.html
^
|
@@ -35,7 +35,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude"
class="diff">
- <ul class="entries">
+ <ul py:if="any([item.diffs or item.props for item in changes])" class="entries">
<py:for each="idx, item in enumerate(changes)">
<li py:if="item.diffs or item.props" class="entry" py:with="comments = item.get('comments')">
<h2 id="${not no_id and 'file%s' % idx or None}" py:choose="">
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/templates/layout.html
^
|
@@ -8,8 +8,7 @@
<py:match path="head" once="true"><head>
<title py:with="title = list(select('title/text()'))">
- <py:if test="title">${title} –</py:if>
- ${' – '.join(filter(None, [project.name, 'Trac']))}
+ <py:if test="title">${title} – </py:if>${project.name or 'Trac'}
</title>
<py:if test="chrome.links">
<py:for each="rel, links in chrome.links.items()">
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/templates/macros.html
^
|
@@ -227,9 +227,12 @@
<py:def function="progress_bar(stats, interval_hrefs, percent=None, legend=True, style=None, stats_href=None)">
<table class="progress" style="$style">
<tr>
- <td py:for="idx, interval in enumerate(stats.intervals)"
+ <td py:for="idx, interval in enumerate(stats.intervals)" py:choose=""
class="$interval.css_class" style="${interval.percent and 'width: %d%%' % interval.percent or 'display: none'}">
- <a href="${interval_hrefs[idx]}"
+ <a py:when="interval_hrefs" href="${interval_hrefs[idx]}"
+ title="${interval.count} of ${stats.count} ${stats.unit}${
+ stats.count != 1 and 's' or ''} ${interval.title}"></a>
+ <a py:otherwise=""
title="${interval.count} of ${stats.count} ${stats.unit}${
stats.count != 1 and 's' or ''} ${interval.title}"></a>
</td>
@@ -238,8 +241,14 @@
<p class="percent">${percent is None and '%d%%' % stats.done_percent or percent}</p>
<dl py:if="legend">
<py:for each="idx, interval in enumerate(stats.intervals)">
- <dt><a href="${interval_hrefs[idx]}">${interval.title.capitalize()} ${stats.unit}s:</a></dt>
- <dd><a href="${interval_hrefs[idx]}">${interval.count}</a></dd>
+ <dt py:choose="">
+ <a py:when="interval_hrefs" href="${interval_hrefs[idx]}">${interval.title.capitalize()} ${stats.unit}s:</a>
+ <a py:otherwise="">${interval.title.capitalize()} ${stats.unit}s:</a>
+ </dt>
+ <dd py:choose="">
+ <a py:when="interval_hrefs" href="${interval_hrefs[idx]}">${interval.count}</a>
+ <a py:otherwise="">${interval.count}</a>
+ </dd>
</py:for>
<py:if test="stats_href">
<dt>/ <a href="${stats_href}">Total ${stats.unit}s:</a></dt>
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/test.py
^
|
@@ -211,7 +211,7 @@
def get_db_cnx(self):
return self.db
- def get_known_users(self, db):
+ def get_known_users(self, cnx=None):
return self.known_users
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/tests/functional/__init__.py
^
|
@@ -40,6 +40,7 @@
Requirements:
- Twill (http://twill.idyll.org/)
- subprocess (py2.4)
+ - lxml for XHTML validation (optional)
"""
import os
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/tests/functional/better_twill.py
^
|
@@ -5,12 +5,21 @@
"""
import os
+from os.path import abspath, dirname, join
import sys
+from pkg_resources import parse_version as pv
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
+# On OSX lxml needs to be imported before twill to avoid Resolver issues
+# somehow caused by the mac specific 'ic' module
+try:
+ from lxml import etree
+except ImportError:
+ pass
+
try:
import twill
except ImportError:
@@ -38,6 +47,57 @@
tc = twill.commands
b = twill.get_browser()
+ # Setup XHTML validation for all retrieved pages
+ try:
+ from lxml import etree
+ except ImportError:
+ print "SKIP: validation of XHTML output in functional tests " \
+ "(no lxml installed)"
+ etree = None
+
+ if etree and pv(etree.__version__) < pv('2.0.0'):
+ # 2.0.7 and 2.1.x are known to work.
+ print "SKIP: validation of XHTML output in functional tests " \
+ "(lxml < 2.0, api incompatibility)"
+ etree = None
+
+ if etree:
+ class _Resolver(etree.Resolver):
+ base_dir = dirname(abspath(__file__))
+
+ def resolve(self, system_url, public_id, context):
+ return self.resolve_filename(join(self.base_dir,
+ system_url.split("/")[-1]),
+ context)
+
+ _parser = etree.XMLParser(dtd_validation=True)
+ _parser.resolvers.add(_Resolver())
+ etree.set_default_parser(_parser)
+
+ def _format_error_log(data, log):
+ msg = []
+ for entry in log:
+ context = data.splitlines()[max(0, entry.line - 5):
+ entry.line + 6]
+ msg.append("\n# %s\n# URL: %s\n# Line %d, column %d\n\n%s\n"
+ % (entry.message, entry.filename,
+ entry.line, entry.column,
+ "\n".join([each.decode('utf-8') for each in context])))
+ return "\n".join(msg).encode('ascii', 'xmlcharrefreplace')
+
+ def _validate_xhtml(func_name, *args, **kwargs):
+ page = b.get_html()
+ if "xhtml1-strict.dtd" not in page:
+ return
+ etree.clear_error_log()
+ try:
+ doc = etree.parse(StringIO(page), base_url=b.get_url())
+ except etree.XMLSyntaxError, e:
+ raise twill.errors.TwillAssertionError(
+ _format_error_log(page, e.error_log))
+
+ b._post_load_hooks.append(_validate_xhtml)
+
# When we can't find something we expected, or find something we didn't
# expect, it helps the debugging effort to have a copy of the html to
# analyze.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/tests/functional/tester.py
^
|
@@ -108,8 +108,9 @@
def go_to_ticket(self, ticketid):
"""Surf to the page for the given ticket ID. Assumes ticket
exists."""
- self.quickjump('#%s' % ticketid)
- tc.url(self.url + "/ticket/%s" % ticketid)
+ ticket_url = self.url + "/ticket/%s" % ticketid
+ tc.go(ticket_url)
+ tc.url(ticket_url)
def go_to_wiki(self, name):
"""Surf to the page for the given wiki page."""
@@ -202,7 +203,7 @@
tc.formvalue('edit', 'text', content)
tc.submit('save')
- tc.url(page_url)
+ tc.url(page_url+'$')
# verify the event shows up in the timeline
self.go_to_timeline()
|
[-]
[+]
|
Added |
Trac-0.11.2.1.tar.gz/trac/tests/functional/xhtml-lat1.ent
^
|
@@ -0,0 +1,196 @@
+<!-- Portions (C) International Organization for Standardization 1986
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % HTMLlat1 PUBLIC
+ "-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
+ %HTMLlat1;
+-->
+
+<!ENTITY nbsp " "> <!-- no-break space = non-breaking space,
+ U+00A0 ISOnum -->
+<!ENTITY iexcl "¡"> <!-- inverted exclamation mark, U+00A1 ISOnum -->
+<!ENTITY cent "¢"> <!-- cent sign, U+00A2 ISOnum -->
+<!ENTITY pound "£"> <!-- pound sign, U+00A3 ISOnum -->
+<!ENTITY curren "¤"> <!-- currency sign, U+00A4 ISOnum -->
+<!ENTITY yen "¥"> <!-- yen sign = yuan sign, U+00A5 ISOnum -->
+<!ENTITY brvbar "¦"> <!-- broken bar = broken vertical bar,
+ U+00A6 ISOnum -->
+<!ENTITY sect "§"> <!-- section sign, U+00A7 ISOnum -->
+<!ENTITY uml "¨"> <!-- diaeresis = spacing diaeresis,
+ U+00A8 ISOdia -->
+<!ENTITY copy "©"> <!-- copyright sign, U+00A9 ISOnum -->
+<!ENTITY ordf "ª"> <!-- feminine ordinal indicator, U+00AA ISOnum -->
+<!ENTITY laquo "«"> <!-- left-pointing double angle quotation mark
+ = left pointing guillemet, U+00AB ISOnum -->
+<!ENTITY not "¬"> <!-- not sign = angled dash,
+ U+00AC ISOnum -->
+<!ENTITY shy "­"> <!-- soft hyphen = discretionary hyphen,
+ U+00AD ISOnum -->
+<!ENTITY reg "®"> <!-- registered sign = registered trade mark sign,
+ U+00AE ISOnum -->
+<!ENTITY macr "¯"> <!-- macron = spacing macron = overline
+ = APL overbar, U+00AF ISOdia -->
+<!ENTITY deg "°"> <!-- degree sign, U+00B0 ISOnum -->
+<!ENTITY plusmn "±"> <!-- plus-minus sign = plus-or-minus sign,
+ U+00B1 ISOnum -->
+<!ENTITY sup2 "²"> <!-- superscript two = superscript digit two
+ = squared, U+00B2 ISOnum -->
+<!ENTITY sup3 "³"> <!-- superscript three = superscript digit three
+ = cubed, U+00B3 ISOnum -->
+<!ENTITY acute "´"> <!-- acute accent = spacing acute,
+ U+00B4 ISOdia -->
+<!ENTITY micro "µ"> <!-- micro sign, U+00B5 ISOnum -->
+<!ENTITY para "¶"> <!-- pilcrow sign = paragraph sign,
+ U+00B6 ISOnum -->
+<!ENTITY middot "·"> <!-- middle dot = Georgian comma
+ = Greek middle dot, U+00B7 ISOnum -->
+<!ENTITY cedil "¸"> <!-- cedilla = spacing cedilla, U+00B8 ISOdia -->
+<!ENTITY sup1 "¹"> <!-- superscript one = superscript digit one,
+ U+00B9 ISOnum -->
+<!ENTITY ordm "º"> <!-- masculine ordinal indicator,
+ U+00BA ISOnum -->
+<!ENTITY raquo "»"> <!-- right-pointing double angle quotation mark
+ = right pointing guillemet, U+00BB ISOnum -->
+<!ENTITY frac14 "¼"> <!-- vulgar fraction one quarter
+ = fraction one quarter, U+00BC ISOnum -->
+<!ENTITY frac12 "½"> <!-- vulgar fraction one half
+ = fraction one half, U+00BD ISOnum -->
+<!ENTITY frac34 "¾"> <!-- vulgar fraction three quarters
+ = fraction three quarters, U+00BE ISOnum -->
+<!ENTITY iquest "¿"> <!-- inverted question mark
+ = turned question mark, U+00BF ISOnum -->
+<!ENTITY Agrave "À"> <!-- latin capital letter A with grave
+ = latin capital letter A grave,
+ U+00C0 ISOlat1 -->
+<!ENTITY Aacute "Á"> <!-- latin capital letter A with acute,
+ U+00C1 ISOlat1 -->
+<!ENTITY Acirc "Â"> <!-- latin capital letter A with circumflex,
+ U+00C2 ISOlat1 -->
+<!ENTITY Atilde "Ã"> <!-- latin capital letter A with tilde,
+ U+00C3 ISOlat1 -->
+<!ENTITY Auml "Ä"> <!-- latin capital letter A with diaeresis,
+ U+00C4 ISOlat1 -->
+<!ENTITY Aring "Å"> <!-- latin capital letter A with ring above
+ = latin capital letter A ring,
+ U+00C5 ISOlat1 -->
+<!ENTITY AElig "Æ"> <!-- latin capital letter AE
+ = latin capital ligature AE,
+ U+00C6 ISOlat1 -->
+<!ENTITY Ccedil "Ç"> <!-- latin capital letter C with cedilla,
+ U+00C7 ISOlat1 -->
+<!ENTITY Egrave "È"> <!-- latin capital letter E with grave,
+ U+00C8 ISOlat1 -->
+<!ENTITY Eacute "É"> <!-- latin capital letter E with acute,
+ U+00C9 ISOlat1 -->
+<!ENTITY Ecirc "Ê"> <!-- latin capital letter E with circumflex,
+ U+00CA ISOlat1 -->
+<!ENTITY Euml "Ë"> <!-- latin capital letter E with diaeresis,
+ U+00CB ISOlat1 -->
+<!ENTITY Igrave "Ì"> <!-- latin capital letter I with grave,
+ U+00CC ISOlat1 -->
+<!ENTITY Iacute "Í"> <!-- latin capital letter I with acute,
+ U+00CD ISOlat1 -->
+<!ENTITY Icirc "Î"> <!-- latin capital letter I with circumflex,
+ U+00CE ISOlat1 -->
+<!ENTITY Iuml "Ï"> <!-- latin capital letter I with diaeresis,
+ U+00CF ISOlat1 -->
+<!ENTITY ETH "Ð"> <!-- latin capital letter ETH, U+00D0 ISOlat1 -->
+<!ENTITY Ntilde "Ñ"> <!-- latin capital letter N with tilde,
+ U+00D1 ISOlat1 -->
+<!ENTITY Ograve "Ò"> <!-- latin capital letter O with grave,
+ U+00D2 ISOlat1 -->
+<!ENTITY Oacute "Ó"> <!-- latin capital letter O with acute,
+ U+00D3 ISOlat1 -->
+<!ENTITY Ocirc "Ô"> <!-- latin capital letter O with circumflex,
+ U+00D4 ISOlat1 -->
+<!ENTITY Otilde "Õ"> <!-- latin capital letter O with tilde,
+ U+00D5 ISOlat1 -->
+<!ENTITY Ouml "Ö"> <!-- latin capital letter O with diaeresis,
+ U+00D6 ISOlat1 -->
+<!ENTITY times "×"> <!-- multiplication sign, U+00D7 ISOnum -->
+<!ENTITY Oslash "Ø"> <!-- latin capital letter O with stroke
+ = latin capital letter O slash,
+ U+00D8 ISOlat1 -->
+<!ENTITY Ugrave "Ù"> <!-- latin capital letter U with grave,
+ U+00D9 ISOlat1 -->
+<!ENTITY Uacute "Ú"> <!-- latin capital letter U with acute,
+ U+00DA ISOlat1 -->
+<!ENTITY Ucirc "Û"> <!-- latin capital letter U with circumflex,
+ U+00DB ISOlat1 -->
+<!ENTITY Uuml "Ü"> <!-- latin capital letter U with diaeresis,
+ U+00DC ISOlat1 -->
+<!ENTITY Yacute "Ý"> <!-- latin capital letter Y with acute,
+ U+00DD ISOlat1 -->
+<!ENTITY THORN "Þ"> <!-- latin capital letter THORN,
+ U+00DE ISOlat1 -->
+<!ENTITY szlig "ß"> <!-- latin small letter sharp s = ess-zed,
+ U+00DF ISOlat1 -->
+<!ENTITY agrave "à"> <!-- latin small letter a with grave
+ = latin small letter a grave,
+ U+00E0 ISOlat1 -->
+<!ENTITY aacute "á"> <!-- latin small letter a with acute,
+ U+00E1 ISOlat1 -->
+<!ENTITY acirc "â"> <!-- latin small letter a with circumflex,
+ U+00E2 ISOlat1 -->
+<!ENTITY atilde "ã"> <!-- latin small letter a with tilde,
+ U+00E3 ISOlat1 -->
+<!ENTITY auml "ä"> <!-- latin small letter a with diaeresis,
+ U+00E4 ISOlat1 -->
+<!ENTITY aring "å"> <!-- latin small letter a with ring above
+ = latin small letter a ring,
+ U+00E5 ISOlat1 -->
+<!ENTITY aelig "æ"> <!-- latin small letter ae
+ = latin small ligature ae, U+00E6 ISOlat1 -->
+<!ENTITY ccedil "ç"> <!-- latin small letter c with cedilla,
+ U+00E7 ISOlat1 -->
+<!ENTITY egrave "è"> <!-- latin small letter e with grave,
+ U+00E8 ISOlat1 -->
+<!ENTITY eacute "é"> <!-- latin small letter e with acute,
+ U+00E9 ISOlat1 -->
+<!ENTITY ecirc "ê"> <!-- latin small letter e with circumflex,
+ U+00EA ISOlat1 -->
+<!ENTITY euml "ë"> <!-- latin small letter e with diaeresis,
+ U+00EB ISOlat1 -->
+<!ENTITY igrave "ì"> <!-- latin small letter i with grave,
+ U+00EC ISOlat1 -->
+<!ENTITY iacute "í"> <!-- latin small letter i with acute,
+ U+00ED ISOlat1 -->
+<!ENTITY icirc "î"> <!-- latin small letter i with circumflex,
+ U+00EE ISOlat1 -->
+<!ENTITY iuml "ï"> <!-- latin small letter i with diaeresis,
+ U+00EF ISOlat1 -->
+<!ENTITY eth "ð"> <!-- latin small letter eth, U+00F0 ISOlat1 -->
+<!ENTITY ntilde "ñ"> <!-- latin small letter n with tilde,
+ U+00F1 ISOlat1 -->
+<!ENTITY ograve "ò"> <!-- latin small letter o with grave,
+ U+00F2 ISOlat1 -->
+<!ENTITY oacute "ó"> <!-- latin small letter o with acute,
+ U+00F3 ISOlat1 -->
+<!ENTITY ocirc "ô"> <!-- latin small letter o with circumflex,
+ U+00F4 ISOlat1 -->
+<!ENTITY otilde "õ"> <!-- latin small letter o with tilde,
+ U+00F5 ISOlat1 -->
+<!ENTITY ouml "ö"> <!-- latin small letter o with diaeresis,
+ U+00F6 ISOlat1 -->
+<!ENTITY divide "÷"> <!-- division sign, U+00F7 ISOnum -->
+<!ENTITY oslash "ø"> <!-- latin small letter o with stroke,
+ = latin small letter o slash,
+ U+00F8 ISOlat1 -->
+<!ENTITY ugrave "ù"> <!-- latin small letter u with grave,
+ U+00F9 ISOlat1 -->
+<!ENTITY uacute "ú"> <!-- latin small letter u with acute,
+ U+00FA ISOlat1 -->
+<!ENTITY ucirc "û"> <!-- latin small letter u with circumflex,
+ U+00FB ISOlat1 -->
+<!ENTITY uuml "ü"> <!-- latin small letter u with diaeresis,
+ U+00FC ISOlat1 -->
+<!ENTITY yacute "ý"> <!-- latin small letter y with acute,
+ U+00FD ISOlat1 -->
+<!ENTITY thorn "þ"> <!-- latin small letter thorn,
+ U+00FE ISOlat1 -->
+<!ENTITY yuml "ÿ"> <!-- latin small letter y with diaeresis,
+ U+00FF ISOlat1 -->
|
[-]
[+]
|
Added |
Trac-0.11.2.1.tar.gz/trac/tests/functional/xhtml-special.ent
^
|
@@ -0,0 +1,80 @@
+<!-- Special characters for XHTML -->
+
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % HTMLspecial PUBLIC
+ "-//W3C//ENTITIES Special for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent">
+ %HTMLspecial;
+-->
+
+<!-- Portions (C) International Organization for Standardization 1986:
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+
+<!-- Relevant ISO entity set is given unless names are newly introduced.
+ New names (i.e., not in ISO 8879 list) do not clash with any
+ existing ISO 8879 entity names. ISO 10646 character numbers
+ are given for each character, in hex. values are decimal
+ conversions of the ISO 10646 values and refer to the document
+ character set. Names are Unicode names.
+-->
+
+<!-- C0 Controls and Basic Latin -->
+<!ENTITY quot """> <!-- quotation mark, U+0022 ISOnum -->
+<!ENTITY amp "&#38;"> <!-- ampersand, U+0026 ISOnum -->
+<!ENTITY lt "&#60;"> <!-- less-than sign, U+003C ISOnum -->
+<!ENTITY gt ">"> <!-- greater-than sign, U+003E ISOnum -->
+<!ENTITY apos "'"> <!-- apostrophe = APL quote, U+0027 ISOnum -->
+
+<!-- Latin Extended-A -->
+<!ENTITY OElig "Œ"> <!-- latin capital ligature OE,
+ U+0152 ISOlat2 -->
+<!ENTITY oelig "œ"> <!-- latin small ligature oe, U+0153 ISOlat2 -->
+<!-- ligature is a misnomer, this is a separate character in some languages -->
+<!ENTITY Scaron "Š"> <!-- latin capital letter S with caron,
+ U+0160 ISOlat2 -->
+<!ENTITY scaron "š"> <!-- latin small letter s with caron,
+ U+0161 ISOlat2 -->
+<!ENTITY Yuml "Ÿ"> <!-- latin capital letter Y with diaeresis,
+ U+0178 ISOlat2 -->
+
+<!-- Spacing Modifier Letters -->
+<!ENTITY circ "ˆ"> <!-- modifier letter circumflex accent,
+ U+02C6 ISOpub -->
+<!ENTITY tilde "˜"> <!-- small tilde, U+02DC ISOdia -->
+
+<!-- General Punctuation -->
+<!ENTITY ensp " "> <!-- en space, U+2002 ISOpub -->
+<!ENTITY emsp " "> <!-- em space, U+2003 ISOpub -->
+<!ENTITY thinsp " "> <!-- thin space, U+2009 ISOpub -->
+<!ENTITY zwnj "‌"> <!-- zero width non-joiner,
+ U+200C NEW RFC 2070 -->
+<!ENTITY zwj "‍"> <!-- zero width joiner, U+200D NEW RFC 2070 -->
+<!ENTITY lrm "‎"> <!-- left-to-right mark, U+200E NEW RFC 2070 -->
+<!ENTITY rlm "‏"> <!-- right-to-left mark, U+200F NEW RFC 2070 -->
+<!ENTITY ndash "–"> <!-- en dash, U+2013 ISOpub -->
+<!ENTITY mdash "—"> <!-- em dash, U+2014 ISOpub -->
+<!ENTITY lsquo "‘"> <!-- left single quotation mark,
+ U+2018 ISOnum -->
+<!ENTITY rsquo "’"> <!-- right single quotation mark,
+ U+2019 ISOnum -->
+<!ENTITY sbquo "‚"> <!-- single low-9 quotation mark, U+201A NEW -->
+<!ENTITY ldquo "“"> <!-- left double quotation mark,
+ U+201C ISOnum -->
+<!ENTITY rdquo "”"> <!-- right double quotation mark,
+ U+201D ISOnum -->
+<!ENTITY bdquo "„"> <!-- double low-9 quotation mark, U+201E NEW -->
+<!ENTITY dagger "†"> <!-- dagger, U+2020 ISOpub -->
+<!ENTITY Dagger "‡"> <!-- double dagger, U+2021 ISOpub -->
+<!ENTITY permil "‰"> <!-- per mille sign, U+2030 ISOtech -->
+<!ENTITY lsaquo "‹"> <!-- single left-pointing angle quotation mark,
+ U+2039 ISO proposed -->
+<!-- lsaquo is proposed but not yet ISO standardized -->
+<!ENTITY rsaquo "›"> <!-- single right-pointing angle quotation mark,
+ U+203A ISO proposed -->
+<!-- rsaquo is proposed but not yet ISO standardized -->
+
+<!-- Currency Symbols -->
+<!ENTITY euro "€"> <!-- euro sign, U+20AC NEW -->
|
[-]
[+]
|
Added |
Trac-0.11.2.1.tar.gz/trac/tests/functional/xhtml-symbol.ent
^
|
@@ -0,0 +1,237 @@
+<!-- Mathematical, Greek and Symbolic characters for XHTML -->
+
+<!-- Character entity set. Typical invocation:
+ <!ENTITY % HTMLsymbol PUBLIC
+ "-//W3C//ENTITIES Symbols for XHTML//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent">
+ %HTMLsymbol;
+-->
+
+<!-- Portions (C) International Organization for Standardization 1986:
+ Permission to copy in any form is granted for use with
+ conforming SGML systems and applications as defined in
+ ISO 8879, provided this notice is included in all copies.
+-->
+
+<!-- Relevant ISO entity set is given unless names are newly introduced.
+ New names (i.e., not in ISO 8879 list) do not clash with any
+ existing ISO 8879 entity names. ISO 10646 character numbers
+ are given for each character, in hex. values are decimal
+ conversions of the ISO 10646 values and refer to the document
+ character set. Names are Unicode names.
+-->
+
+<!-- Latin Extended-B -->
+<!ENTITY fnof "ƒ"> <!-- latin small letter f with hook = function
+ = florin, U+0192 ISOtech -->
+
+<!-- Greek -->
+<!ENTITY Alpha "Α"> <!-- greek capital letter alpha, U+0391 -->
+<!ENTITY Beta "Β"> <!-- greek capital letter beta, U+0392 -->
+<!ENTITY Gamma "Γ"> <!-- greek capital letter gamma,
+ U+0393 ISOgrk3 -->
+<!ENTITY Delta "Δ"> <!-- greek capital letter delta,
+ U+0394 ISOgrk3 -->
+<!ENTITY Epsilon "Ε"> <!-- greek capital letter epsilon, U+0395 -->
+<!ENTITY Zeta "Ζ"> <!-- greek capital letter zeta, U+0396 -->
+<!ENTITY Eta "Η"> <!-- greek capital letter eta, U+0397 -->
+<!ENTITY Theta "Θ"> <!-- greek capital letter theta,
+ U+0398 ISOgrk3 -->
+<!ENTITY Iota "Ι"> <!-- greek capital letter iota, U+0399 -->
+<!ENTITY Kappa "Κ"> <!-- greek capital letter kappa, U+039A -->
+<!ENTITY Lambda "Λ"> <!-- greek capital letter lamda,
+ U+039B ISOgrk3 -->
+<!ENTITY Mu "Μ"> <!-- greek capital letter mu, U+039C -->
+<!ENTITY Nu "Ν"> <!-- greek capital letter nu, U+039D -->
+<!ENTITY Xi "Ξ"> <!-- greek capital letter xi, U+039E ISOgrk3 -->
+<!ENTITY Omicron "Ο"> <!-- greek capital letter omicron, U+039F -->
+<!ENTITY Pi "Π"> <!-- greek capital letter pi, U+03A0 ISOgrk3 -->
+<!ENTITY Rho "Ρ"> <!-- greek capital letter rho, U+03A1 -->
+<!-- there is no Sigmaf, and no U+03A2 character either -->
+<!ENTITY Sigma "Σ"> <!-- greek capital letter sigma,
+ U+03A3 ISOgrk3 -->
+<!ENTITY Tau "Τ"> <!-- greek capital letter tau, U+03A4 -->
+<!ENTITY Upsilon "Υ"> <!-- greek capital letter upsilon,
+ U+03A5 ISOgrk3 -->
+<!ENTITY Phi "Φ"> <!-- greek capital letter phi,
+ U+03A6 ISOgrk3 -->
+<!ENTITY Chi "Χ"> <!-- greek capital letter chi, U+03A7 -->
+<!ENTITY Psi "Ψ"> <!-- greek capital letter psi,
+ U+03A8 ISOgrk3 -->
+<!ENTITY Omega "Ω"> <!-- greek capital letter omega,
+ U+03A9 ISOgrk3 -->
+
+<!ENTITY alpha "α"> <!-- greek small letter alpha,
+ U+03B1 ISOgrk3 -->
+<!ENTITY beta "β"> <!-- greek small letter beta, U+03B2 ISOgrk3 -->
+<!ENTITY gamma "γ"> <!-- greek small letter gamma,
+ U+03B3 ISOgrk3 -->
+<!ENTITY delta "δ"> <!-- greek small letter delta,
+ U+03B4 ISOgrk3 -->
+<!ENTITY epsilon "ε"> <!-- greek small letter epsilon,
+ U+03B5 ISOgrk3 -->
+<!ENTITY zeta "ζ"> <!-- greek small letter zeta, U+03B6 ISOgrk3 -->
+<!ENTITY eta "η"> <!-- greek small letter eta, U+03B7 ISOgrk3 -->
+<!ENTITY theta "θ"> <!-- greek small letter theta,
+ U+03B8 ISOgrk3 -->
+<!ENTITY iota "ι"> <!-- greek small letter iota, U+03B9 ISOgrk3 -->
+<!ENTITY kappa "κ"> <!-- greek small letter kappa,
+ U+03BA ISOgrk3 -->
+<!ENTITY lambda "λ"> <!-- greek small letter lamda,
+ U+03BB ISOgrk3 -->
+<!ENTITY mu "μ"> <!-- greek small letter mu, U+03BC ISOgrk3 -->
+<!ENTITY nu "ν"> <!-- greek small letter nu, U+03BD ISOgrk3 -->
+<!ENTITY xi "ξ"> <!-- greek small letter xi, U+03BE ISOgrk3 -->
+<!ENTITY omicron "ο"> <!-- greek small letter omicron, U+03BF NEW -->
+<!ENTITY pi "π"> <!-- greek small letter pi, U+03C0 ISOgrk3 -->
+<!ENTITY rho "ρ"> <!-- greek small letter rho, U+03C1 ISOgrk3 -->
+<!ENTITY sigmaf "ς"> <!-- greek small letter final sigma,
+ U+03C2 ISOgrk3 -->
+<!ENTITY sigma "σ"> <!-- greek small letter sigma,
+ U+03C3 ISOgrk3 -->
+<!ENTITY tau "τ"> <!-- greek small letter tau, U+03C4 ISOgrk3 -->
+<!ENTITY upsilon "υ"> <!-- greek small letter upsilon,
+ U+03C5 ISOgrk3 -->
+<!ENTITY phi "φ"> <!-- greek small letter phi, U+03C6 ISOgrk3 -->
+<!ENTITY chi "χ"> <!-- greek small letter chi, U+03C7 ISOgrk3 -->
+<!ENTITY psi "ψ"> <!-- greek small letter psi, U+03C8 ISOgrk3 -->
+<!ENTITY omega "ω"> <!-- greek small letter omega,
+ U+03C9 ISOgrk3 -->
+<!ENTITY thetasym "ϑ"> <!-- greek theta symbol,
+ U+03D1 NEW -->
+<!ENTITY upsih "ϒ"> <!-- greek upsilon with hook symbol,
+ U+03D2 NEW -->
+<!ENTITY piv "ϖ"> <!-- greek pi symbol, U+03D6 ISOgrk3 -->
+
+<!-- General Punctuation -->
+<!ENTITY bull "•"> <!-- bullet = black small circle,
+ U+2022 ISOpub -->
+<!-- bullet is NOT the same as bullet operator, U+2219 -->
+<!ENTITY hellip "…"> <!-- horizontal ellipsis = three dot leader,
+ U+2026 ISOpub -->
+<!ENTITY prime "′"> <!-- prime = minutes = feet, U+2032 ISOtech -->
+<!ENTITY Prime "″"> <!-- double prime = seconds = inches,
+ U+2033 ISOtech -->
+<!ENTITY oline "‾"> <!-- overline = spacing overscore,
+ U+203E NEW -->
+<!ENTITY frasl "⁄"> <!-- fraction slash, U+2044 NEW -->
+
+<!-- Letterlike Symbols -->
+<!ENTITY weierp "℘"> <!-- script capital P = power set
+ = Weierstrass p, U+2118 ISOamso -->
+<!ENTITY image "ℑ"> <!-- black-letter capital I = imaginary part,
+ U+2111 ISOamso -->
+<!ENTITY real "ℜ"> <!-- black-letter capital R = real part symbol,
+ U+211C ISOamso -->
+<!ENTITY trade "™"> <!-- trade mark sign, U+2122 ISOnum -->
+<!ENTITY alefsym "ℵ"> <!-- alef symbol = first transfinite cardinal,
+ U+2135 NEW -->
+<!-- alef symbol is NOT the same as hebrew letter alef,
+ U+05D0 although the same glyph could be used to depict both characters -->
+
+<!-- Arrows -->
+<!ENTITY larr "←"> <!-- leftwards arrow, U+2190 ISOnum -->
+<!ENTITY uarr "↑"> <!-- upwards arrow, U+2191 ISOnum-->
+<!ENTITY rarr "→"> <!-- rightwards arrow, U+2192 ISOnum -->
+<!ENTITY darr "↓"> <!-- downwards arrow, U+2193 ISOnum -->
+<!ENTITY harr "↔"> <!-- left right arrow, U+2194 ISOamsa -->
+<!ENTITY crarr "↵"> <!-- downwards arrow with corner leftwards
+ = carriage return, U+21B5 NEW -->
+<!ENTITY lArr "⇐"> <!-- leftwards double arrow, U+21D0 ISOtech -->
+<!-- Unicode does not say that lArr is the same as the 'is implied by' arrow
+ but also does not have any other character for that function. So lArr can
+ be used for 'is implied by' as ISOtech suggests -->
+<!ENTITY uArr "⇑"> <!-- upwards double arrow, U+21D1 ISOamsa -->
+<!ENTITY rArr "⇒"> <!-- rightwards double arrow,
+ U+21D2 ISOtech -->
+<!-- Unicode does not say this is the 'implies' character but does not have
+ another character with this function so rArr can be used for 'implies'
+ as ISOtech suggests -->
+<!ENTITY dArr "⇓"> <!-- downwards double arrow, U+21D3 ISOamsa -->
+<!ENTITY hArr "⇔"> <!-- left right double arrow,
+ U+21D4 ISOamsa -->
+
+<!-- Mathematical Operators -->
+<!ENTITY forall "∀"> <!-- for all, U+2200 ISOtech -->
+<!ENTITY part "∂"> <!-- partial differential, U+2202 ISOtech -->
+<!ENTITY exist "∃"> <!-- there exists, U+2203 ISOtech -->
+<!ENTITY empty "∅"> <!-- empty set = null set, U+2205 ISOamso -->
+<!ENTITY nabla "∇"> <!-- nabla = backward difference,
+ U+2207 ISOtech -->
+<!ENTITY isin "∈"> <!-- element of, U+2208 ISOtech -->
+<!ENTITY notin "∉"> <!-- not an element of, U+2209 ISOtech -->
+<!ENTITY ni "∋"> <!-- contains as member, U+220B ISOtech -->
+<!ENTITY prod "∏"> <!-- n-ary product = product sign,
+ U+220F ISOamsb -->
+<!-- prod is NOT the same character as U+03A0 'greek capital letter pi' though
+ the same glyph might be used for both -->
+<!ENTITY sum "∑"> <!-- n-ary summation, U+2211 ISOamsb -->
+<!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
+ though the same glyph might be used for both -->
+<!ENTITY minus "−"> <!-- minus sign, U+2212 ISOtech -->
+<!ENTITY lowast "∗"> <!-- asterisk operator, U+2217 ISOtech -->
+<!ENTITY radic "√"> <!-- square root = radical sign,
+ U+221A ISOtech -->
+<!ENTITY prop "∝"> <!-- proportional to, U+221D ISOtech -->
+<!ENTITY infin "∞"> <!-- infinity, U+221E ISOtech -->
+<!ENTITY ang "∠"> <!-- angle, U+2220 ISOamso -->
+<!ENTITY and "∧"> <!-- logical and = wedge, U+2227 ISOtech -->
+<!ENTITY or "∨"> <!-- logical or = vee, U+2228 ISOtech -->
+<!ENTITY cap "∩"> <!-- intersection = cap, U+2229 ISOtech -->
+<!ENTITY cup "∪"> <!-- union = cup, U+222A ISOtech -->
+<!ENTITY int "∫"> <!-- integral, U+222B ISOtech -->
+<!ENTITY there4 "∴"> <!-- therefore, U+2234 ISOtech -->
+<!ENTITY sim "∼"> <!-- tilde operator = varies with = similar to,
+ U+223C ISOtech -->
+<!-- tilde operator is NOT the same character as the tilde, U+007E,
+ although the same glyph might be used to represent both -->
+<!ENTITY cong "≅"> <!-- approximately equal to, U+2245 ISOtech -->
+<!ENTITY asymp "≈"> <!-- almost equal to = asymptotic to,
+ U+2248 ISOamsr -->
+<!ENTITY ne "≠"> <!-- not equal to, U+2260 ISOtech -->
+<!ENTITY equiv "≡"> <!-- identical to, U+2261 ISOtech -->
+<!ENTITY le "≤"> <!-- less-than or equal to, U+2264 ISOtech -->
+<!ENTITY ge "≥"> <!-- greater-than or equal to,
+ U+2265 ISOtech -->
+<!ENTITY sub "⊂"> <!-- subset of, U+2282 ISOtech -->
+<!ENTITY sup "⊃"> <!-- superset of, U+2283 ISOtech -->
+<!ENTITY nsub "⊄"> <!-- not a subset of, U+2284 ISOamsn -->
+<!ENTITY sube "⊆"> <!-- subset of or equal to, U+2286 ISOtech -->
+<!ENTITY supe "⊇"> <!-- superset of or equal to,
+ U+2287 ISOtech -->
+<!ENTITY oplus "⊕"> <!-- circled plus = direct sum,
+ U+2295 ISOamsb -->
+<!ENTITY otimes "⊗"> <!-- circled times = vector product,
+ U+2297 ISOamsb -->
+<!ENTITY perp "⊥"> <!-- up tack = orthogonal to = perpendicular,
+ U+22A5 ISOtech -->
+<!ENTITY sdot "⋅"> <!-- dot operator, U+22C5 ISOamsb -->
+<!-- dot operator is NOT the same character as U+00B7 middle dot -->
+
+<!-- Miscellaneous Technical -->
+<!ENTITY lceil "⌈"> <!-- left ceiling = APL upstile,
+ U+2308 ISOamsc -->
+<!ENTITY rceil "⌉"> <!-- right ceiling, U+2309 ISOamsc -->
+<!ENTITY lfloor "⌊"> <!-- left floor = APL downstile,
+ U+230A ISOamsc -->
+<!ENTITY rfloor "⌋"> <!-- right floor, U+230B ISOamsc -->
+<!ENTITY lang "〈"> <!-- left-pointing angle bracket = bra,
+ U+2329 ISOtech -->
+<!-- lang is NOT the same character as U+003C 'less than sign'
+ or U+2039 'single left-pointing angle quotation mark' -->
+<!ENTITY rang "〉"> <!-- right-pointing angle bracket = ket,
+ U+232A ISOtech -->
+<!-- rang is NOT the same character as U+003E 'greater than sign'
+ or U+203A 'single right-pointing angle quotation mark' -->
+
+<!-- Geometric Shapes -->
+<!ENTITY loz "◊"> <!-- lozenge, U+25CA ISOpub -->
+
+<!-- Miscellaneous Symbols -->
+<!ENTITY spades "♠"> <!-- black spade suit, U+2660 ISOpub -->
+<!-- black here seems to mean filled as opposed to hollow -->
+<!ENTITY clubs "♣"> <!-- black club suit = shamrock,
+ U+2663 ISOpub -->
+<!ENTITY hearts "♥"> <!-- black heart suit = valentine,
+ U+2665 ISOpub -->
+<!ENTITY diams "♦"> <!-- black diamond suit, U+2666 ISOpub -->
|
[-]
[+]
|
Added |
Trac-0.11.2.1.tar.gz/trac/tests/functional/xhtml1-strict.dtd
^
|
@@ -0,0 +1,978 @@
+<!--
+ Extensible HTML version 1.0 Strict DTD
+
+ This is the same as HTML 4 Strict except for
+ changes due to the differences between XML and SGML.
+
+ Namespace = http://www.w3.org/1999/xhtml
+
+ For further information, see: http://www.w3.org/TR/xhtml1
+
+ Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
+ All Rights Reserved.
+
+ This DTD module is identified by the PUBLIC and SYSTEM identifiers:
+
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+
+ $Revision: 1.1 $
+ $Date: 2002/08/01 13:56:03 $
+
+-->
+
+<!--================ Character mnemonic entities =========================-->
+
+<!ENTITY % HTMLlat1 PUBLIC
+ "-//W3C//ENTITIES Latin 1 for XHTML//EN"
+ "xhtml-lat1.ent">
+%HTMLlat1;
+
+<!ENTITY % HTMLsymbol PUBLIC
+ "-//W3C//ENTITIES Symbols for XHTML//EN"
+ "xhtml-symbol.ent">
+%HTMLsymbol;
+
+<!ENTITY % HTMLspecial PUBLIC
+ "-//W3C//ENTITIES Special for XHTML//EN"
+ "xhtml-special.ent">
+%HTMLspecial;
+
+<!--================== Imported Names ====================================-->
+
+<!ENTITY % ContentType "CDATA">
+ <!-- media type, as per [RFC2045] -->
+
+<!ENTITY % ContentTypes "CDATA">
+ <!-- comma-separated list of media types, as per [RFC2045] -->
+
+<!ENTITY % Charset "CDATA">
+ <!-- a character encoding, as per [RFC2045] -->
+
+<!ENTITY % Charsets "CDATA">
+ <!-- a space separated list of character encodings, as per [RFC2045] -->
+
+<!ENTITY % LanguageCode "NMTOKEN">
+ <!-- a language code, as per [RFC3066] -->
+
+<!ENTITY % Character "CDATA">
+ <!-- a single character, as per section 2.2 of [XML] -->
+
+<!ENTITY % Number "CDATA">
+ <!-- one or more digits -->
+
+<!ENTITY % LinkTypes "CDATA">
+ <!-- space-separated list of link types -->
+
+<!ENTITY % MediaDesc "CDATA">
+ <!-- single or comma-separated list of media descriptors -->
+
+<!ENTITY % URI "CDATA">
+ <!-- a Uniform Resource Identifier, see [RFC2396] -->
+
+<!ENTITY % UriList "CDATA">
+ <!-- a space separated list of Uniform Resource Identifiers -->
+
+<!ENTITY % Datetime "CDATA">
+ <!-- date and time information. ISO date format -->
+
+<!ENTITY % Script "CDATA">
+ <!-- script expression -->
+
+<!ENTITY % StyleSheet "CDATA">
+ <!-- style sheet data -->
+
+<!ENTITY % Text "CDATA">
+ <!-- used for titles etc. -->
+
+<!ENTITY % Length "CDATA">
+ <!-- nn for pixels or nn% for percentage length -->
+
+<!ENTITY % MultiLength "CDATA">
+ <!-- pixel, percentage, or relative -->
+
+<!ENTITY % Pixels "CDATA">
+ <!-- integer representing length in pixels -->
+
+<!-- these are used for image maps -->
+
+<!ENTITY % Shape "(rect|circle|poly|default)">
+
+<!ENTITY % Coords "CDATA">
+ <!-- comma separated list of lengths -->
+
+<!--=================== Generic Attributes ===============================-->
+
+<!-- core attributes common to most elements
+ id document-wide unique id
+ class space separated list of classes
+ style associated style info
+ title advisory title/amplification
+-->
+<!ENTITY % coreattrs
+ "id ID #IMPLIED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED"
+ >
+
+<!-- internationalization attributes
+ lang language code (backwards compatible)
+ xml:lang language code (as per XML 1.0 spec)
+ dir direction for weak/neutral text
+-->
+<!ENTITY % i18n
+ "lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #IMPLIED"
+ >
+
+<!-- attributes for common UI events
+ onclick a pointer button was clicked
+ ondblclick a pointer button was double clicked
+ onmousedown a pointer button was pressed down
+ onmouseup a pointer button was released
+ onmousemove a pointer was moved onto the element
+ onmouseout a pointer was moved away from the element
+ onkeypress a key was pressed and released
+ onkeydown a key was pressed down
+ onkeyup a key was released
+-->
+<!ENTITY % events
+ "onclick %Script; #IMPLIED
+ ondblclick %Script; #IMPLIED
+ onmousedown %Script; #IMPLIED
+ onmouseup %Script; #IMPLIED
+ onmouseover %Script; #IMPLIED
+ onmousemove %Script; #IMPLIED
+ onmouseout %Script; #IMPLIED
+ onkeypress %Script; #IMPLIED
+ onkeydown %Script; #IMPLIED
+ onkeyup %Script; #IMPLIED"
+ >
+
+<!-- attributes for elements that can get the focus
+ accesskey accessibility key character
+ tabindex position in tabbing order
+ onfocus the element got the focus
+ onblur the element lost the focus
+-->
+<!ENTITY % focus
+ "accesskey %Character; #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED"
+ >
+
+<!ENTITY % attrs "%coreattrs; %i18n; %events;">
+
+<!--=================== Text Elements ====================================-->
+
+<!ENTITY % special.pre
+ "br | span | bdo | map">
+
+
+<!ENTITY % special
+ "%special.pre; | object | img ">
+
+<!ENTITY % fontstyle "tt | i | b | big | small ">
+
+<!ENTITY % phrase "em | strong | dfn | code | q |
+ samp | kbd | var | cite | abbr | acronym | sub | sup ">
+
+<!ENTITY % inline.forms "input | select | textarea | label | button">
+
+<!-- these can occur at block or inline level -->
+<!ENTITY % misc.inline "ins | del | script">
+
+<!-- these can only occur at block level -->
+<!ENTITY % misc "noscript | %misc.inline;">
+
+<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
+
+<!-- %Inline; covers inline or "text-level" elements -->
+<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
+
+<!--================== Block level elements ==============================-->
+
+<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
+<!ENTITY % lists "ul | ol | dl">
+<!ENTITY % blocktext "pre | hr | blockquote | address">
+
+<!ENTITY % block
+ "p | %heading; | div | %lists; | %blocktext; | fieldset | table">
+
+<!ENTITY % Block "(%block; | form | %misc;)*">
+
+<!-- %Flow; mixes block and inline and is used for list items etc. -->
+<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
+
+<!--================== Content models for exclusions =====================-->
+
+<!-- a elements use %Inline; excluding a -->
+
+<!ENTITY % a.content
+ "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
+
+<!-- pre uses %Inline excluding big, small, sup or sup -->
+
+<!ENTITY % pre.content
+ "(#PCDATA | a | %fontstyle; | %phrase; | %special.pre; | %misc.inline;
+ | %inline.forms;)*">
+
+<!-- form uses %Block; excluding form -->
+
+<!ENTITY % form.content "(%block; | %misc;)*">
+
+<!-- button uses %Flow; but excludes a, form and form controls -->
+
+<!ENTITY % button.content
+ "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
+ table | %special; | %fontstyle; | %phrase; | %misc;)*">
+
+<!--================ Document Structure ==================================-->
+
+<!-- the namespace URI designates the document profile -->
+
+<!ELEMENT html (head, body)>
+<!ATTLIST html
+ %i18n;
+ id ID #IMPLIED
+ xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
+ >
+
+<!--================ Document Head =======================================-->
+
+<!ENTITY % head.misc "(script|style|meta|link|object)*">
+
+<!-- content model is %head.misc; combined with a single
+ title and an optional base element in any order -->
+
+<!ELEMENT head (%head.misc;,
+ ((title, %head.misc;, (base, %head.misc;)?) |
+ (base, %head.misc;, (title, %head.misc;))))>
+
+<!ATTLIST head
+ %i18n;
+ id ID #IMPLIED
+ profile %URI; #IMPLIED
+ >
+
+<!-- The title element is not considered part of the flow of text.
+ It should be displayed, for example as the page header or
+ window title. Exactly one title is required per document.
+ -->
+<!ELEMENT title (#PCDATA)>
+<!ATTLIST title
+ %i18n;
+ id ID #IMPLIED
+ >
+
+<!-- document base URI -->
+
+<!ELEMENT base EMPTY>
+<!ATTLIST base
+ href %URI; #REQUIRED
+ id ID #IMPLIED
+ >
+
+<!-- generic metainformation -->
+<!ELEMENT meta EMPTY>
+<!ATTLIST meta
+ %i18n;
+ id ID #IMPLIED
+ http-equiv CDATA #IMPLIED
+ name CDATA #IMPLIED
+ content CDATA #REQUIRED
+ scheme CDATA #IMPLIED
+ >
+
+<!--
+ Relationship values can be used in principle:
+
+ a) for document specific toolbars/menus when used
+ with the link element in document head e.g.
+ start, contents, previous, next, index, end, help
+ b) to link to a separate style sheet (rel="stylesheet")
+ c) to make a link to a script (rel="script")
+ d) by stylesheets to control how collections of
+ html nodes are rendered into printed documents
+ e) to make a link to a printable version of this document
+ e.g. a PostScript or PDF version (rel="alternate" media="print")
+-->
+
+<!ELEMENT link EMPTY>
+<!ATTLIST link
+ %attrs;
+ charset %Charset; #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ type %ContentType; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ media %MediaDesc; #IMPLIED
+ >
+
+<!-- style info, which may include CDATA sections -->
+<!ELEMENT style (#PCDATA)>
+<!ATTLIST style
+ %i18n;
+ id ID #IMPLIED
+ type %ContentType; #REQUIRED
+ media %MediaDesc; #IMPLIED
+ title %Text; #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- script statements, which may include CDATA sections -->
+<!ELEMENT script (#PCDATA)>
+<!ATTLIST script
+ id ID #IMPLIED
+ charset %Charset; #IMPLIED
+ type %ContentType; #REQUIRED
+ src %URI; #IMPLIED
+ defer (defer) #IMPLIED
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!-- alternate content container for non script-based rendering -->
+
+<!ELEMENT noscript %Block;>
+<!ATTLIST noscript
+ %attrs;
+ >
+
+<!--=================== Document Body ====================================-->
+
+<!ELEMENT body %Block;>
+<!ATTLIST body
+ %attrs;
+ onload %Script; #IMPLIED
+ onunload %Script; #IMPLIED
+ >
+
+<!ELEMENT div %Flow;> <!-- generic language/style container -->
+<!ATTLIST div
+ %attrs;
+ >
+
+<!--=================== Paragraphs =======================================-->
+
+<!ELEMENT p %Inline;>
+<!ATTLIST p
+ %attrs;
+ >
+
+<!--=================== Headings =========================================-->
+
+<!--
+ There are six levels of headings from h1 (the most important)
+ to h6 (the least important).
+-->
+
+<!ELEMENT h1 %Inline;>
+<!ATTLIST h1
+ %attrs;
+ >
+
+<!ELEMENT h2 %Inline;>
+<!ATTLIST h2
+ %attrs;
+ >
+
+<!ELEMENT h3 %Inline;>
+<!ATTLIST h3
+ %attrs;
+ >
+
+<!ELEMENT h4 %Inline;>
+<!ATTLIST h4
+ %attrs;
+ >
+
+<!ELEMENT h5 %Inline;>
+<!ATTLIST h5
+ %attrs;
+ >
+
+<!ELEMENT h6 %Inline;>
+<!ATTLIST h6
+ %attrs;
+ >
+
+<!--=================== Lists ============================================-->
+
+<!-- Unordered list -->
+
+<!ELEMENT ul (li)+>
+<!ATTLIST ul
+ %attrs;
+ >
+
+<!-- Ordered (numbered) list -->
+
+<!ELEMENT ol (li)+>
+<!ATTLIST ol
+ %attrs;
+ >
+
+<!-- list item -->
+
+<!ELEMENT li %Flow;>
+<!ATTLIST li
+ %attrs;
+ >
+
+<!-- definition lists - dt for term, dd for its definition -->
+
+<!ELEMENT dl (dt|dd)+>
+<!ATTLIST dl
+ %attrs;
+ >
+
+<!ELEMENT dt %Inline;>
+<!ATTLIST dt
+ %attrs;
+ >
+
+<!ELEMENT dd %Flow;>
+<!ATTLIST dd
+ %attrs;
+ >
+
+<!--=================== Address ==========================================-->
+
+<!-- information on author -->
+
+<!ELEMENT address %Inline;>
+<!ATTLIST address
+ %attrs;
+ >
+
+<!--=================== Horizontal Rule ==================================-->
+
+<!ELEMENT hr EMPTY>
+<!ATTLIST hr
+ %attrs;
+ >
+
+<!--=================== Preformatted Text ================================-->
+
+<!-- content is %Inline; excluding "img|object|big|small|sub|sup" -->
+
+<!ELEMENT pre %pre.content;>
+<!ATTLIST pre
+ %attrs;
+ xml:space (preserve) #FIXED 'preserve'
+ >
+
+<!--=================== Block-like Quotes ================================-->
+
+<!ELEMENT blockquote %Block;>
+<!ATTLIST blockquote
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!--=================== Inserted/Deleted Text ============================-->
+
+<!--
+ ins/del are allowed in block and inline content, but its
+ inappropriate to include block content within an ins element
+ occurring in inline content.
+-->
+<!ELEMENT ins %Flow;>
+<!ATTLIST ins
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!ELEMENT del %Flow;>
+<!ATTLIST del
+ %attrs;
+ cite %URI; #IMPLIED
+ datetime %Datetime; #IMPLIED
+ >
+
+<!--================== The Anchor Element ================================-->
+
+<!-- content is %Inline; except that anchors shouldn't be nested -->
+
+<!ELEMENT a %a.content;>
+<!ATTLIST a
+ %attrs;
+ %focus;
+ charset %Charset; #IMPLIED
+ type %ContentType; #IMPLIED
+ name NMTOKEN #IMPLIED
+ href %URI; #IMPLIED
+ hreflang %LanguageCode; #IMPLIED
+ rel %LinkTypes; #IMPLIED
+ rev %LinkTypes; #IMPLIED
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ >
+
+<!--===================== Inline Elements ================================-->
+
+<!ELEMENT span %Inline;> <!-- generic language/style container -->
+<!ATTLIST span
+ %attrs;
+ >
+
+<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
+<!ATTLIST bdo
+ %coreattrs;
+ %events;
+ lang %LanguageCode; #IMPLIED
+ xml:lang %LanguageCode; #IMPLIED
+ dir (ltr|rtl) #REQUIRED
+ >
+
+<!ELEMENT br EMPTY> <!-- forced line break -->
+<!ATTLIST br
+ %coreattrs;
+ >
+
+<!ELEMENT em %Inline;> <!-- emphasis -->
+<!ATTLIST em %attrs;>
+
+<!ELEMENT strong %Inline;> <!-- strong emphasis -->
+<!ATTLIST strong %attrs;>
+
+<!ELEMENT dfn %Inline;> <!-- definitional -->
+<!ATTLIST dfn %attrs;>
+
+<!ELEMENT code %Inline;> <!-- program code -->
+<!ATTLIST code %attrs;>
+
+<!ELEMENT samp %Inline;> <!-- sample -->
+<!ATTLIST samp %attrs;>
+
+<!ELEMENT kbd %Inline;> <!-- something user would type -->
+<!ATTLIST kbd %attrs;>
+
+<!ELEMENT var %Inline;> <!-- variable -->
+<!ATTLIST var %attrs;>
+
+<!ELEMENT cite %Inline;> <!-- citation -->
+<!ATTLIST cite %attrs;>
+
+<!ELEMENT abbr %Inline;> <!-- abbreviation -->
+<!ATTLIST abbr %attrs;>
+
+<!ELEMENT acronym %Inline;> <!-- acronym -->
+<!ATTLIST acronym %attrs;>
+
+<!ELEMENT q %Inline;> <!-- inlined quote -->
+<!ATTLIST q
+ %attrs;
+ cite %URI; #IMPLIED
+ >
+
+<!ELEMENT sub %Inline;> <!-- subscript -->
+<!ATTLIST sub %attrs;>
+
+<!ELEMENT sup %Inline;> <!-- superscript -->
+<!ATTLIST sup %attrs;>
+
+<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
+<!ATTLIST tt %attrs;>
+
+<!ELEMENT i %Inline;> <!-- italic font -->
+<!ATTLIST i %attrs;>
+
+<!ELEMENT b %Inline;> <!-- bold font -->
+<!ATTLIST b %attrs;>
+
+<!ELEMENT big %Inline;> <!-- bigger font -->
+<!ATTLIST big %attrs;>
+
+<!ELEMENT small %Inline;> <!-- smaller font -->
+<!ATTLIST small %attrs;>
+
+<!--==================== Object ======================================-->
+<!--
+ object is used to embed objects as part of HTML pages.
+ param elements should precede other content. Parameters
+ can also be expressed as attribute/value pairs on the
+ object element itself when brevity is desired.
+-->
+
+<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
+<!ATTLIST object
+ %attrs;
+ declare (declare) #IMPLIED
+ classid %URI; #IMPLIED
+ codebase %URI; #IMPLIED
+ data %URI; #IMPLIED
+ type %ContentType; #IMPLIED
+ codetype %ContentType; #IMPLIED
+ archive %UriList; #IMPLIED
+ standby %Text; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ name NMTOKEN #IMPLIED
+ tabindex %Number; #IMPLIED
+ >
+
+<!--
+ param is used to supply a named property value.
+ In XML it would seem natural to follow RDF and support an
+ abbreviated syntax where the param elements are replaced
+ by attribute value pairs on the object start tag.
+-->
+<!ELEMENT param EMPTY>
+<!ATTLIST param
+ id ID #IMPLIED
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ valuetype (data|ref|object) "data"
+ type %ContentType; #IMPLIED
+ >
+
+<!--=================== Images ===========================================-->
+
+<!--
+ To avoid accessibility problems for people who aren't
+ able to see the image, you should provide a text
+ description using the alt and longdesc attributes.
+ In addition, avoid the use of server-side image maps.
+ Note that in this DTD there is no name attribute. That
+ is only available in the transitional and frameset DTD.
+-->
+
+<!ELEMENT img EMPTY>
+<!ATTLIST img
+ %attrs;
+ src %URI; #REQUIRED
+ alt %Text; #REQUIRED
+ longdesc %URI; #IMPLIED
+ height %Length; #IMPLIED
+ width %Length; #IMPLIED
+ usemap %URI; #IMPLIED
+ ismap (ismap) #IMPLIED
+ >
+
+<!-- usemap points to a map element which may be in this document
+ or an external document, although the latter is not widely supported -->
+
+<!--================== Client-side image maps ============================-->
+
+<!-- These can be placed in the same document or grouped in a
+ separate document although this isn't yet widely supported -->
+
+<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
+<!ATTLIST map
+ %i18n;
+ %events;
+ id ID #REQUIRED
+ class CDATA #IMPLIED
+ style %StyleSheet; #IMPLIED
+ title %Text; #IMPLIED
+ name NMTOKEN #IMPLIED
+ >
+
+<!ELEMENT area EMPTY>
+<!ATTLIST area
+ %attrs;
+ %focus;
+ shape %Shape; "rect"
+ coords %Coords; #IMPLIED
+ href %URI; #IMPLIED
+ nohref (nohref) #IMPLIED
+ alt %Text; #REQUIRED
+ >
+
+<!--================ Forms ===============================================-->
+<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
+
+<!ATTLIST form
+ %attrs;
+ action %URI; #REQUIRED
+ method (get|post) "get"
+ enctype %ContentType; "application/x-www-form-urlencoded"
+ onsubmit %Script; #IMPLIED
+ onreset %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ accept-charset %Charsets; #IMPLIED
+ >
+
+<!--
+ Each label must not contain more than ONE field
+ Label elements shouldn't be nested.
+-->
+<!ELEMENT label %Inline;>
+<!ATTLIST label
+ %attrs;
+ for IDREF #IMPLIED
+ accesskey %Character; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ >
+
+<!ENTITY % InputType
+ "(text | password | checkbox |
+ radio | submit | reset |
+ file | hidden | image | button)"
+ >
+
+<!-- the name attribute is required for all but submit & reset -->
+
+<!ELEMENT input EMPTY> <!-- form control -->
+<!ATTLIST input
+ %attrs;
+ %focus;
+ type %InputType; "text"
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ checked (checked) #IMPLIED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ size CDATA #IMPLIED
+ maxlength %Number; #IMPLIED
+ src %URI; #IMPLIED
+ alt CDATA #IMPLIED
+ usemap %URI; #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ accept %ContentTypes; #IMPLIED
+ >
+
+<!ELEMENT select (optgroup|option)+> <!-- option selector -->
+<!ATTLIST select
+ %attrs;
+ name CDATA #IMPLIED
+ size %Number; #IMPLIED
+ multiple (multiple) #IMPLIED
+ disabled (disabled) #IMPLIED
+ tabindex %Number; #IMPLIED
+ onfocus %Script; #IMPLIED
+ onblur %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!ELEMENT optgroup (option)+> <!-- option group -->
+<!ATTLIST optgroup
+ %attrs;
+ disabled (disabled) #IMPLIED
+ label %Text; #REQUIRED
+ >
+
+<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
+<!ATTLIST option
+ %attrs;
+ selected (selected) #IMPLIED
+ disabled (disabled) #IMPLIED
+ label %Text; #IMPLIED
+ value CDATA #IMPLIED
+ >
+
+<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
+<!ATTLIST textarea
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ rows %Number; #REQUIRED
+ cols %Number; #REQUIRED
+ disabled (disabled) #IMPLIED
+ readonly (readonly) #IMPLIED
+ onselect %Script; #IMPLIED
+ onchange %Script; #IMPLIED
+ >
+
+<!--
+ The fieldset element is used to group form fields.
+ Only one legend element should occur in the content
+ and if present should only be preceded by whitespace.
+-->
+<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
+<!ATTLIST fieldset
+ %attrs;
+ >
+
+<!ELEMENT legend %Inline;> <!-- fieldset label -->
+<!ATTLIST legend
+ %attrs;
+ accesskey %Character; #IMPLIED
+ >
+
+<!--
+ Content is %Flow; excluding a, form and form controls
+-->
+<!ELEMENT button %button.content;> <!-- push button -->
+<!ATTLIST button
+ %attrs;
+ %focus;
+ name CDATA #IMPLIED
+ value CDATA #IMPLIED
+ type (button|submit|reset) "submit"
+ disabled (disabled) #IMPLIED
+ >
+
+<!--======================= Tables =======================================-->
+
+<!-- Derived from IETF HTML table standard, see [RFC1942] -->
+
+<!--
+ The border attribute sets the thickness of the frame around the
+ table. The default units are screen pixels.
+
+ The frame attribute specifies which parts of the frame around
+ the table should be rendered. The values are not the same as
+ CALS to avoid a name clash with the valign attribute.
+-->
+<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
+
+<!--
+ The rules attribute defines which rules to draw between cells:
+
+ If rules is absent then assume:
+ "none" if border is absent or border="0" otherwise "all"
+-->
+
+<!ENTITY % TRules "(none | groups | rows | cols | all)">
+
+<!-- horizontal alignment attributes for cell contents
+
+ char alignment char, e.g. char=':'
+ charoff offset for alignment char
+-->
+<!ENTITY % cellhalign
+ "align (left|center|right|justify|char) #IMPLIED
+ char %Character; #IMPLIED
+ charoff %Length; #IMPLIED"
+ >
+
+<!-- vertical alignment attributes for cell contents -->
+<!ENTITY % cellvalign
+ "valign (top|middle|bottom|baseline) #IMPLIED"
+ >
+
+<!ELEMENT table
+ (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
+<!ELEMENT caption %Inline;>
+<!ELEMENT thead (tr)+>
+<!ELEMENT tfoot (tr)+>
+<!ELEMENT tbody (tr)+>
+<!ELEMENT colgroup (col)*>
+<!ELEMENT col EMPTY>
+<!ELEMENT tr (th|td)+>
+<!ELEMENT th %Flow;>
+<!ELEMENT td %Flow;>
+
+<!ATTLIST table
+ %attrs;
+ summary %Text; #IMPLIED
+ width %Length; #IMPLIED
+ border %Pixels; #IMPLIED
+ frame %TFrame; #IMPLIED
+ rules %TRules; #IMPLIED
+ cellspacing %Length; #IMPLIED
+ cellpadding %Length; #IMPLIED
+ >
+
+<!ATTLIST caption
+ %attrs;
+ >
+
+<!--
+colgroup groups a set of col elements. It allows you to group
+several semantically related columns together.
+-->
+<!ATTLIST colgroup
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ col elements define the alignment properties for cells in
+ one or more columns.
+
+ The width attribute specifies the width of the columns, e.g.
+
+ width=64 width in screen pixels
+ width=0.5* relative width of 0.5
+
+ The span attribute causes the attributes of one
+ col element to apply to more than one column.
+-->
+<!ATTLIST col
+ %attrs;
+ span %Number; "1"
+ width %MultiLength; #IMPLIED
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!--
+ Use thead to duplicate headers when breaking table
+ across page boundaries, or for static headers when
+ tbody sections are rendered in scrolling panel.
+
+ Use tfoot to duplicate footers when breaking table
+ across page boundaries, or for static footers when
+ tbody sections are rendered in scrolling panel.
+
+ Use multiple tbody sections when rules are needed
+ between groups of table rows.
+-->
+<!ATTLIST thead
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tfoot
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tbody
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST tr
+ %attrs;
+ %cellhalign;
+ %cellvalign;
+ >
+
+
+<!-- Scope is simpler than headers attribute for common tables -->
+<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
+
+<!-- th is for headers, td for data and for cells acting as both -->
+
+<!ATTLIST th
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ >
+
+<!ATTLIST td
+ %attrs;
+ abbr %Text; #IMPLIED
+ axis CDATA #IMPLIED
+ headers IDREFS #IMPLIED
+ scope %Scope; #IMPLIED
+ rowspan %Number; "1"
+ colspan %Number; "1"
+ %cellhalign;
+ %cellvalign;
+ >
+
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/tests/wikisyntax.py
^
|
@@ -79,8 +79,8 @@
[attachment:foo.txt other file]
------------------------------
<p>
-<a class="missing attachment" rel="nofollow">attachment:foo.txt</a>
-<a class="missing attachment" rel="nofollow">other file</a>
+<a class="missing attachment">attachment:foo.txt</a>
+<a class="missing attachment">other file</a>
</p>
------------------------------
============================== attachment: "raw" links
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/admin.py
^
|
@@ -206,9 +206,18 @@
self.config.save()
req.redirect(req.href.admin(cat, page))
+ # Get ticket count
+ db = self.env.get_db_cnx()
+ cursor = db.cursor()
+ milestones = []
+ for milestone in model.Milestone.select(self.env, db=db):
+ cursor.execute("SELECT COUNT(*) FROM ticket "
+ "WHERE milestone=%s", (milestone.name, ))
+ milestones.append((milestone, cursor.fetchone()[0]))
+
data = {
'view': 'list',
- 'milestones': model.Milestone.select(self.env),
+ 'milestones': milestones,
'default': self.config.get('ticket', 'default_milestone'),
}
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/api.py
^
|
@@ -16,12 +16,16 @@
import re
from datetime import datetime
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
from genshi.builder import tag
from trac.config import *
from trac.core import *
-from trac.perm import IPermissionRequestor, PermissionSystem, PermissionError
+from trac.perm import IPermissionRequestor, PermissionCache, PermissionSystem
from trac.resource import IResourceManager
from trac.util import Ranges
from trac.util.compat import set, sorted
@@ -157,6 +161,7 @@
def __init__(self):
self.log.debug('action controllers for ticket workflow: %r' %
[c.__class__.__name__ for c in self.action_controllers])
+ self._fields_lock = threading.RLock()
# Public API
@@ -185,6 +190,26 @@
def get_ticket_fields(self):
"""Returns the list of fields available for tickets."""
+ # This is now cached - as it makes quite a number of things faster,
+ # e.g. #6436
+ if self._fields is None:
+ self._fields_lock.acquire()
+ try:
+ self._fields = self._get_ticket_fields()
+ finally:
+ self._fields_lock.release()
+ return [f.copy() for f in self._fields]
+
+ def reset_ticket_fields(self):
+ self._fields_lock.acquire()
+ try:
+ self._fields = None
+ self.config.touch() # brute force approach for now
+ finally:
+ self._fields_lock.release()
+
+ _fields = None
+ def _get_ticket_fields(self):
from trac.ticket import model
db = self.env.get_db_cnx()
@@ -195,16 +220,10 @@
field = {'name': name, 'type': 'text', 'label': name.title()}
fields.append(field)
- # Owner field, can be text or drop-down depending on configuration
+ # Owner field, by default text but can be changed dynamically
+ # into a drop-down depending on configuration (restrict_owner=true)
field = {'name': 'owner', 'label': 'Owner'}
- if self.restrict_owner:
- field['type'] = 'select'
- perm = PermissionSystem(self.env)
- field['options'] = perm.get_users_with_permission('TICKET_MODIFY')
- field['options'].sort()
- field['optional'] = True
- else:
- field['type'] = 'text'
+ field['type'] = 'text'
fields.append(field)
# Description
@@ -256,6 +275,16 @@
return fields
def get_custom_fields(self):
+ if self._custom_fields is None:
+ self._fields_lock.acquire()
+ try:
+ self._custom_fields = self._get_custom_fields()
+ finally:
+ self._fields_lock.release()
+ return [f.copy() for f in self._custom_fields]
+
+ _custom_fields = None
+ def _get_custom_fields(self):
fields = []
config = self.config['ticket-custom']
for name in [option for option, value in config.options()
@@ -280,6 +309,23 @@
fields.sort(lambda x, y: cmp(x['order'], y['order']))
return fields
+ def eventually_restrict_owner(self, field, ticket=None):
+ """Restrict given owner field to be a list of users having
+ the TICKET_MODIFY permission (for the given ticket)
+ """
+ if self.restrict_owner:
+ field['type'] = 'select'
+ possible_owners = []
+ for user in PermissionSystem(self.env) \
+ .get_users_with_permission('TICKET_MODIFY'):
+ if not ticket or \
+ 'TICKET_MODIFY' in PermissionCache(self.env, user,
+ ticket.resource):
+ possible_owners.append(user)
+ possible_owners.sort()
+ field['options'] = possible_owners
+ field['optional'] = True
+
# IPermissionRequestor methods
def get_permission_actions(self):
@@ -318,7 +364,8 @@
num = r.a
ticket = formatter.resource('ticket', num)
from trac.ticket.model import Ticket
- if Ticket.id_is_valid(num):
+ if Ticket.id_is_valid(num) and \
+ 'TICKET_VIEW' in formatter.perm(ticket):
# TODO: watch #6436 and when done, attempt to retrieve
# ticket directly (try: Ticket(self.env, num) ...)
cursor = formatter.db.cursor()
@@ -330,10 +377,6 @@
href = formatter.href.ticket(num) + params + fragment
return tag.a(label, class_='%s ticket' % status,
title=title, href=href)
- else:
- href = formatter.href.ticket(num)
- return tag.a(label, class_='missing ticket', href=href,
- rel="nofollow")
else:
ranges = str(r)
if params:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/default_workflow.py
^
|
@@ -169,11 +169,7 @@
# the process of being modified, we need to base our information on the
# pre-modified state so that we don't try to do two (or more!) steps at
# once and get really confused.
- if 'status' in ticket._old:
- status = ticket._old['status']
- else:
- status = ticket['status']
- status = status or 'new'
+ status = ticket._old.get('status', ticket['status']) or 'new'
allowed_actions = []
for action_name, action_info in self.actions.items():
@@ -218,6 +214,7 @@
this_action = self.actions[action]
status = this_action['newstate']
operations = this_action['operations']
+ current_owner = ticket._old.get('owner', ticket['owner'] or '(none)')
control = [] # default to nothing
hints = []
@@ -244,20 +241,27 @@
owner = req.args.get(id, req.authname)
control.append(tag(['to ', tag.input(type='text', id=id,
name=id, value=owner)]))
- hints.append(_("The owner will change"))
+ hints.append(_("The owner will change from %(current_owner)s",
+ current_owner=current_owner))
elif len(owners) == 1:
control.append(tag('to %s ' % owners[0]))
if ticket['owner'] != owners[0]:
- hints.append(_("The owner will change to %s") % owners[0])
+ hints.append(_("The owner will change from "
+ "%(current_owner)s to %(selected_owner)s",
+ current_owner=current_owner,
+ selected_owner=owners[0]))
else:
control.append(tag([_("to "), tag.select(
[tag.option(x, selected=(x == selected_owner or None))
for x in owners],
id=id, name=id)]))
- hints.append(_("The owner will change"))
+ hints.append(_("The owner will change from %(current_owner)s",
+ current_owner=current_owner))
if 'set_owner_to_self' in operations and \
- ticket['owner'] != req.authname:
- hints.append(_("The owner will change to %s") % req.authname)
+ ticket._old.get('owner', ticket['owner']) != req.authname:
+ hints.append(_("The owner will change from %(current_owner)s "
+ "to %(authname)s", current_owner=current_owner,
+ authname=req.authname))
if 'set_resolution' in operations:
if this_action.has_key('set_resolution'):
resolutions = [x.strip() for x in
@@ -283,7 +287,8 @@
id=id, name=id)]))
hints.append(_("The resolution will be set"))
if 'leave_status' in operations:
- control.append('as %s ' % ticket['status'])
+ control.append('as %s ' % ticket._old.get('status',
+ ticket['status']))
else:
if status != '*':
hints.append(_("Next status will be '%s'") % status)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/model.py
^
|
@@ -100,7 +100,9 @@
self.id = tkt_id
for i in range(len(std_fields)):
- self.values[std_fields[i]] = row[i] or ''
+ value = row[i]
+ if value is not None:
+ self.values[std_fields[i]] = row[i]
self.time_created = datetime.fromtimestamp(row[len(std_fields)], utc)
self.time_changed = datetime.fromtimestamp(row[len(std_fields) + 1], utc)
@@ -131,6 +133,17 @@
value = value.strip()
self.values[name] = value
+ def get_value_or_default(self, name):
+ """Return the value of a field or the default value if it is
+ undefined"""
+ try:
+ return self.values[name]
+ except KeyError:
+ field = [field for field in self.fields if field['name'] == name]
+ if field:
+ return field[0].get('value')
+ return None
+
def populate(self, values):
"""Populate the ticket with 'suitable' values from a dictionary"""
field_names = [f['name'] for f in self.fields]
@@ -395,6 +408,7 @@
db.commit()
self.value = self._old_value = None
self.name = self._old_name = None
+ TicketSystem(self.env).reset_ticket_fields()
def insert(self, db=None):
assert not self.exists, 'Cannot insert existing %s' % self.type
@@ -420,6 +434,7 @@
db.commit()
self._old_name = self.name
self._old_value = self.value
+ TicketSystem(self.env).reset_ticket_fields()
def update(self, db=None):
assert self.exists, 'Cannot update non-existent %s' % self.type
@@ -446,6 +461,7 @@
db.commit()
self._old_name = self.name
self._old_value = self.value
+ TicketSystem(self.env).reset_ticket_fields()
def select(cls, env, db=None):
if not db:
@@ -532,6 +548,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def insert(self, db=None):
assert not self.exists, 'Cannot insert existing component'
@@ -551,6 +568,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def update(self, db=None):
assert self.exists, 'Cannot update non-existent component'
@@ -576,6 +594,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def select(cls, env, db=None):
if not db:
@@ -656,6 +675,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def insert(self, db=None):
assert self.name, 'Cannot create milestone with no name'
@@ -675,6 +695,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def update(self, db=None):
assert self.name, 'Cannot update milestone with no name'
@@ -700,6 +721,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def select(cls, env, include_completed=True, db=None):
if not db:
@@ -762,6 +784,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def insert(self, db=None):
assert not self.exists, 'Cannot insert existing version'
@@ -781,6 +804,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def update(self, db=None):
assert self.exists, 'Cannot update non-existent version'
@@ -806,6 +830,7 @@
if handle_ta:
db.commit()
+ TicketSystem(self.env).reset_ticket_fields()
def select(cls, env, db=None):
if not db:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/notification.py
^
|
@@ -22,7 +22,7 @@
from trac.notification import NotifyEmail
from trac.util import md5
from trac.util.datefmt import to_timestamp
-from trac.util.text import CRLF, wrap, to_unicode
+from trac.util.text import CRLF, wrap, to_unicode, obfuscate_email_address
from genshi.template.text import TextTemplate
@@ -82,7 +82,7 @@
if not change['permanent']: # attachment with same time...
continue
change_data.update({
- 'author': change['author'],
+ 'author': obfuscate_email_address(change['author']),
'comment': wrap(change['comment'], self.COLS, ' ', ' ',
CRLF)
})
@@ -119,6 +119,9 @@
changes_body += chgcc
self.prev_cc += old and self.parse_cc(old) or []
else:
+ if field in ['owner', 'reporter']:
+ old = obfuscate_email_address(old)
+ new = obfuscate_email_address(new)
newv = new
l = 7 + len(field)
chg = wrap('%s => %s' % (old, new), self.COLS - l, '',
@@ -176,6 +179,8 @@
if not tkt.values.has_key(fname):
continue
fval = tkt[fname]
+ if fname in ['owner', 'reporter']:
+ fval = obfuscate_email_address(fval)
if f['type'] == 'textarea' or '\n' in unicode(fval):
big.append((fname.capitalize(), CRLF.join(fval.splitlines())))
else:
@@ -196,8 +201,10 @@
def diff_cc(self, old, new):
oldcc = NotifyEmail.addrsep_re.split(old)
newcc = NotifyEmail.addrsep_re.split(new)
- added = [x for x in newcc if x and x not in oldcc]
- removed = [x for x in oldcc if x and x not in newcc]
+ added = [obfuscate_email_address(x) \
+ for x in newcc if x and x not in oldcc]
+ removed = [obfuscate_email_address(x) \
+ for x in oldcc if x and x not in newcc]
return (added, removed)
def format_hdr(self):
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/query.py
^
|
@@ -35,7 +35,7 @@
from trac.util.presentation import Paginator
from trac.util.text import shorten_line
from trac.util.translation import _
-from trac.web import IRequestHandler
+from trac.web import parse_query_string, IRequestHandler
from trac.web.href import Href
from trac.web.chrome import add_ctxtnav, add_link, add_script, add_stylesheet, \
INavigationContributor, Chrome
@@ -147,7 +147,8 @@
val = neg + mode + val # add mode of comparison
processed_values.append(val)
try:
- field = str(field)
+ if isinstance(field, unicode):
+ field = field.encode('utf-8')
if field in kw_strs:
kw[field] = processed_values[0]
elif field in kw_arys:
@@ -241,7 +242,11 @@
# tuple([repr(a) for a in args]))
cnt = 0
- cursor.execute(count_sql, args);
+ try:
+ cursor.execute(count_sql, args);
+ except:
+ db.rollback()
+ raise
for cnt, in cursor:
break
self.env.log.debug("Count results in Query: %d" % cnt)
@@ -269,7 +274,11 @@
'pages in the query', page=self.page))
self.env.log.debug("Query SQL: " + sql % tuple([repr(a) for a in args]))
- cursor.execute(sql, args)
+ try:
+ cursor.execute(sql, args)
+ except:
+ db.rollback()
+ raise
columns = get_column_names(cursor)
fields = []
for column in columns:
@@ -383,7 +392,7 @@
add_cols(self.group)
if self.rows:
add_cols('reporter', *self.rows)
- add_cols('priority', 'time', 'changetime', self.order)
+ add_cols('status', 'priority', 'time', 'changetime', self.order)
cols.extend([c for c in self.constraints.keys() if not c in cols])
custom_fields = [f['name'] for f in self.fields if 'custom' in f]
@@ -500,15 +509,13 @@
args.append(constraint_sql[1])
clauses = filter(None, clauses)
- if clauses or cached_ids:
- sql.append("\nWHERE ")
if clauses:
+ sql.append("\nWHERE ")
sql.append(" AND ".join(clauses))
- if cached_ids:
- if clauses:
+ if cached_ids:
sql.append(" OR ")
- sql.append("id in (%s)" % (','.join(
- [str(id) for id in cached_ids])))
+ sql.append("id in (%s)" % (','.join(
+ [str(id) for id in cached_ids])))
sql.append("\nORDER BY ")
order_cols = [(self.order, self.desc)]
@@ -519,42 +526,28 @@
col = name + '.value'
else:
col = 't.' + name
+ desc = desc and ' DESC' or ''
# FIXME: This is a somewhat ugly hack. Can we also have the
# column type for this? If it's an integer, we do first
# one, if text, we do 'else'
if name in ('id', 'time', 'changetime'):
- if desc:
- sql.append("COALESCE(%s,0)=0 DESC," % col)
- else:
- sql.append("COALESCE(%s,0)=0," % col)
+ sql.append("COALESCE(%s,0)=0%s," % (col, desc))
else:
- if desc:
- sql.append("COALESCE(%s,'')='' DESC," % col)
- else:
- sql.append("COALESCE(%s,'')=''," % col)
+ sql.append("COALESCE(%s,'')=''%s," % (col, desc))
if name in enum_columns:
# These values must be compared as ints, not as strings
db = self.env.get_db_cnx()
- if desc:
- sql.append(db.cast(col, 'int') + ' DESC')
- else:
- sql.append(db.cast(col, 'int'))
- elif name in ('milestone', 'version'):
- if name == 'milestone':
- time_col = 'milestone.due'
- else:
- time_col = 'version.time'
- if desc:
- sql.append("COALESCE(%s,0)=0 DESC,%s DESC,%s DESC"
- % (time_col, time_col, col))
- else:
- sql.append("COALESCE(%s,0)=0,%s,%s"
- % (time_col, time_col, col))
+ sql.append(db.cast(col, 'int') + desc)
+ elif name == 'milestone':
+ sql.append("COALESCE(milestone.completed,0)=0%s,"
+ "milestone.completed%s,"
+ "COALESCE(milestone.due,0)=0%s,milestone.due%s,"
+ "%s%s" % (desc, desc, desc, desc, col, desc))
+ elif name == 'version':
+ sql.append("COALESCE(version.time,0)=0%s,version.time%s,%s%s"
+ % (desc, desc, col, desc))
else:
- if desc:
- sql.append("%s DESC" % col)
- else:
- sql.append("%s" % col)
+ sql.append("%s%s" % (col, desc))
if name == self.group and not name == self.order:
sql.append(",")
if self.order != 'id':
@@ -594,8 +587,6 @@
fields = {}
for field in self.fields:
- if field['type'] == 'textarea':
- continue
field_data = {}
field_data.update(field)
del field_data['name']
@@ -610,6 +601,10 @@
{'name': _("is"), 'value': ""},
{'name': _("is not"), 'value': "!"}
]
+ modes['textarea'] = [
+ {'name': _("contains"), 'value': "~"},
+ {'name': _("doesn't contain"), 'value': "!~"},
+ ]
modes['select'] = [
{'name': _("is"), 'value': ""},
{'name': _("is not"), 'value': "!"}
@@ -694,13 +689,21 @@
implements(IRequestHandler, INavigationContributor, IWikiSyntaxProvider,
IContentConverter)
- default_query = Option('query', 'default_query',
- default='status!=closed&owner=$USER',
- doc='The default query for authenticated users.')
+ default_query = Option('query', 'default_query',
+ default='status!=closed&owner=$USER',
+ doc="""The default query for authenticated users. The query is either
+ in [TracQuery#QueryLanguage query language] syntax, or a URL query
+ string starting with `?` as used in `query:`
+ [TracQuery#UsingTracLinks Trac links].
+ (''since 0.11.2'')""")
default_anonymous_query = Option('query', 'default_anonymous_query',
- default='status!=closed&cc~=$USER',
- doc='The default query for anonymous users.')
+ default='status!=closed&cc~=$USER',
+ doc="""The default query for anonymous users. The query is either
+ in [TracQuery#QueryLanguage query language] syntax, or a URL query
+ string starting with `?` as used in `query:`
+ [TracQuery#UsingTracLinks Trac links].
+ (''since 0.11.2'')""")
items_per_page = IntOption('query', 'items_per_page', 100,
"""Number of tickets displayed per page in ticket queries,
@@ -745,48 +748,58 @@
req.perm.assert_permission('TICKET_VIEW')
constraints = self._get_constraints(req)
+ args = req.args
if not constraints and not 'order' in req.args:
# If no constraints are given in the URL, use the default ones.
if req.authname and req.authname != 'anonymous':
- qstring = self.default_query
- user = req.authname
+ qstring = self.default_query
+ user = req.authname
else:
email = req.session.get('email')
name = req.session.get('name')
- qstring = self.default_anonymous_query
- user = email or name or None
+ qstring = self.default_anonymous_query
+ user = email or name or None
- if user:
- qstring = qstring.replace('$USER', user)
- self.log.debug('QueryModule: Using default query: %s', str(qstring))
- constraints = Query.from_string(self.env, qstring).constraints
- # Ensure no field constraints that depend on $USER are used
- # if we have no username.
- for field, vals in constraints.items():
- for val in vals:
- if val.endswith('$USER'):
- del constraints[field]
+ self.log.debug('QueryModule: Using default query: %s', str(qstring))
+ if qstring.startswith('?'):
+ ticket_fields = [f['name'] for f in
+ TicketSystem(self.env).get_ticket_fields()]
+ ticket_fields.append('id')
+ args = parse_query_string(qstring[1:])
+ constraints = dict([(k, args.getlist(k)) for k in args
+ if k in ticket_fields])
+ else:
+ constraints = Query.from_string(self.env, qstring).constraints
+ # Substitute $USER, or ensure no field constraints that depend
+ # on $USER are used if we have no username.
+ for field, vals in constraints.items():
+ for (i, val) in enumerate(vals):
+ if user:
+ vals[i] = val.replace('$USER', user)
+ elif val.endswith('$USER'):
+ del constraints[field]
+ break
- cols = req.args.get('col')
+ cols = args.get('col')
if isinstance(cols, basestring):
cols = [cols]
# Since we don't show 'id' as an option to the user,
# we need to re-insert it here.
if cols and 'id' not in cols:
cols.insert(0, 'id')
- rows = req.args.get('row', [])
+ rows = args.get('row', [])
if isinstance(rows, basestring):
rows = [rows]
format = req.args.get('format')
- max = req.args.get('max')
+ max = args.get('max')
if max is None and format in ('csv', 'tab'):
max = 0 # unlimited unless specified explicitly
query = Query(self.env, req.args.get('report'),
- constraints, cols, req.args.get('order'),
- 'desc' in req.args, req.args.get('group'),
- 'groupdesc' in req.args, 'verbose' in req.args,
+ constraints, cols, args.get('order'),
+ 'desc' in args, args.get('group'),
+ 'groupdesc' in args, 'verbose' in args,
rows,
- req.args.get('page'),
+ args.get('page'),
max)
if 'update' in req.args:
@@ -805,7 +818,7 @@
if format:
Mimeview(self.env).send_converted(req, 'trac.ticket.Query', query,
- format, 'query')
+ format, filename=None)
return self.display_html(req, query)
@@ -872,6 +885,9 @@
orig_time = query_time
context = Context.from_request(req, 'query')
+ owner_field = [f for f in query.fields if f['name'] == 'owner']
+ if owner_field:
+ TicketSystem(self.env).eventually_restrict_owner(owner_field[0])
data = query.template_data(context, tickets, orig_list, orig_time, req)
# For clients without JavaScript, we add a new constraint here if
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/report.py
^
|
@@ -72,7 +72,7 @@
# IRequestHandler methods
def match_request(self, req):
- match = re.match(r'/report(?:/([0-9]+))?', req.path_info)
+ match = re.match(r'/report(?:/(?:([0-9]+)|-1))?$', req.path_info)
if match:
if match.group(1):
req.args['id'] = match.group(1)
@@ -312,11 +312,11 @@
data['paginator'] = paginator
if paginator.has_next_page:
next_href = req.href.report(id, asc=asc, sort=sort_col,
- USER=user, page=page + 1)
+ page=page + 1, **args)
add_link(req, 'next', next_href, _('Next Page'))
if paginator.has_previous_page:
prev_href = req.href.report(id, asc=asc, sort=sort_col,
- USER=user, page=page - 1)
+ page=page - 1, **args)
add_link(req, 'prev', prev_href, _('Previous Page'))
pagedata = []
@@ -486,10 +486,10 @@
req.session['query_tickets'] = \
' '.join([str(int(row['id']))
for rg in row_groups for row in rg[1]])
- #FIXME: I am not sure the extra args are necessary
req.session['query_href'] = \
- req.href.report(id, asc=not asc and '0' or None,
- sort=sort_col, USER=user, page=page)
+ req.href.report(id, asc=req.args.get('asc', None),
+ sort=req.args.get('sort', None),
+ page=page, **args)
# Kludge: we have to clear the other query session
# variables, but only if the above succeeded
for var in ('query_constraints', 'query_time'):
@@ -500,7 +500,7 @@
return 'report_view.html', data, None
def add_alternate_links(self, req, args):
- params = args
+ params = args.copy()
if 'sort' in req.args:
params['sort'] = req.args['sort']
if 'asc' in req.args:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/roadmap.py
^
|
@@ -42,7 +42,7 @@
from trac.web.chrome import add_link, add_stylesheet, add_warning, \
INavigationContributor
from trac.wiki.api import IWikiSyntaxProvider
-from trac.wiki.formatter import format_to_html
+from trac.wiki.formatter import format_to
class ITicketGroupStatsProvider(Interface):
def get_ticket_group_stats(ticket_ids):
@@ -243,7 +243,7 @@
for arg in [kv for kv in group.get('query_args', '').split(',')
if '=' in kv]:
k, v = [a.strip() for a in arg.split('=', 1)]
- query_args[k] = v
+ query_args.setdefault(k, []).append(v)
stat.add_interval(group.get('label', group['name']),
group_cnt, query_args,
group.get('css_class', group['name']),
@@ -316,7 +316,7 @@
# IRequestHandler methods
def match_request(self, req):
- return re.match(r'/roadmap/?', req.path_info) is not None
+ return req.path_info == '/roadmap'
def process_request(self, req):
milestone_realm = Resource('milestone')
@@ -532,14 +532,13 @@
elif field == 'title':
return tag('Milestone ', tag.em(milestone.id), ' completed')
elif field == 'description':
- return format_to_html(self.env, context(resource=milestone),
- shorten_line(description))
+ return format_to(self.env, None, context(resource=milestone),
+ description)
# IRequestHandler methods
def match_request(self, req):
- import re, urllib
- match = re.match(r'/milestone(?:/(.+))?', req.path_info)
+ match = re.match(r'/milestone(?:/(.+))?$', req.path_info)
if match:
if match.group(1):
req.args['id'] = match.group(1)
@@ -582,7 +581,7 @@
retarget_to = None
if req.args.has_key('retarget'):
- retarget_to = req.args.get('target')
+ retarget_to = req.args.get('target') or None
milestone.delete(retarget_to, req.authname)
db.commit()
req.redirect(req.href.roadmap())
@@ -784,13 +783,15 @@
# should simply be false if the milestone doesn't exist in the db
# (related to #4130)
href = context.href.milestone(name)
- if milestone and milestone.exists and \
- 'MILESTONE_VIEW' in context.perm(milestone.resource):
- closed = milestone.is_completed and 'closed ' or ''
- return tag.a(label, class_='%smilestone' % closed, href=href+extra)
- else:
- return tag.a(label, class_='missing milestone', href=href+extra,
- rel="nofollow")
+ if milestone and milestone.exists:
+ if 'MILESTONE_VIEW' in context.perm(milestone.resource):
+ closed = milestone.is_completed and 'closed ' or ''
+ return tag.a(label, class_='%smilestone' % closed,
+ href=href + extra)
+ elif 'MILESTONE_CREATE' in context.perm('milestone', name):
+ return tag.a(label, class_='missing milestone', href=href + extra,
+ rel='nofollow')
+ return tag.a(label, class_='missing milestone')
# IResourceManager methods
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/templates/milestone_edit.html
^
|
@@ -61,7 +61,7 @@
<label>
<input type="text" id="completeddate" name="completeddate"
size="${len(datetime_hint)}" title="Format: ${datetime_hint}"
- value="${format_date(milestone.completed) or format_date}" />
+ value="${format_datetime(milestone.completed)}" />
<em>Format: ${datetime_hint}</em>
</label>
<py:if test="milestones">
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/templates/milestone_view.html
^
|
@@ -24,7 +24,7 @@
<py:choose>
<p py:when="milestone.completed" class="date">
Completed ${dateinfo(milestone.completed)} ago
- (${format_date(milestone.completed)})
+ (${format_datetime(milestone.completed)})
</p>
<p py:when="milestone.is_late" class="date">
<strong>${dateinfo(milestone.due)} late</strong>
@@ -66,7 +66,9 @@
<a py:otherwise="" href="${group.stats_href}">${group.name}</a>
</th>
<td>
- ${progress_bar(group.stats, group.interval_hrefs,
+ ${progress_bar(group.stats, (group.interval_hrefs, None)
+ [grouped_by in ['owner', 'reporter']
+ and group.name != format_author(group.name)],
'%d / %d' % (group.stats.done_count, group.stats.count),
legend=False, style="width: %d%%" % (group.percent_of_max_total * 0.8))}
</td>
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/templates/query.html
^
|
@@ -35,7 +35,8 @@
${wiki_to_html(context(report_resource), description)}
</div>
- <form id="query" method="post" action="${href.query()}">
+ <form id="query" method="post" action="${href.query()}"
+ py:with="field_names = sorted(fields.iterkeys(), key=lambda name: labels[name].lower())">
<fieldset id="filters">
<input py:if="'id' in query.constraints" type="hidden" name="id" value="${query.constraints['id']}" />
<legend class="foldable">Filters</legend>
@@ -43,10 +44,10 @@
<tbody>
<tr style="height: 1px"><td colspan="4"></td></tr>
</tbody>
- <py:for each="field_name, field in fields.items()">
+ <py:for each="field_name in field_names" py:with="field = fields[field_name]">
<py:for each="constraint_name, constraint in constraints.items()">
<tbody py:if="field_name == constraint_name"
- py:with="multiline = field.type in ('select', 'text')">
+ py:with="multiline = field.type in ('select', 'text', 'textarea')">
<py:for each="constraint_idx, constraint_value in enumerate(constraint['values'])">
<tr class="${field_name}" py:if="multiline or constraint_idx == 0">
<py:choose test="constraint_idx">
@@ -66,9 +67,9 @@
</py:choose>
<td class="filter" colspan="${field.type in ('radio', 'checkbox') and 2 or None}"
- py:choose="field.type">
+ py:choose="">
- <py:when test="'select'">
+ <py:when test="field.type == 'select'">
<select name="${constraint_name}">
<option></option>
<option py:for="option in field.options"
@@ -77,7 +78,7 @@
</select>
</py:when>
- <py:when test="'radio'">
+ <py:when test="field.type == 'radio'">
<py:for each="option in field.options">
<input type="checkbox" id="${field_name}_$option" name="${field_name}"
value="$option"
@@ -87,7 +88,7 @@
</py:for>
</py:when>
- <py:when test="'checkbox'">
+ <py:when test="field.type == 'checkbox'">
<input type="radio" id="${field_name}_on" name="$field_name" value="1"
checked="${constraint.mode != '!' or constraint_value == '1' or None}" />
<label for="${field_name}_on">yes</label>
@@ -96,7 +97,7 @@
<label for="${field_name}_off">no</label>
</py:when>
- <py:when test="'text'">
+ <py:when test="field.type in ('text', 'textarea')">
<input type="text" name="${field_name}" value="$constraint_value" size="42" />
</py:when>
@@ -117,7 +118,7 @@
<label for="add_filter">Add filter</label>
<select name="add_filter" id="add_filter">
<option></option>
- <option py:for="field_name, field in fields.items()"
+ <option py:for="field_name in field_names" py:with="field = fields[field_name]"
value="$field_name"
disabled="${(field.type == 'radio' and
field_name in constraints and
@@ -151,10 +152,11 @@
<label for="group">Group results by</label>
<select name="group" id="group">
<option></option>
- <option py:for="field_name, field in fields.items()"
- py:if="field.type in ('select', 'radio') or field_name in ('owner', 'reporter')"
- selected="${field_name == query.group or None}"
- value="${field_name}">${field.label}</option>
+ <py:for each="field_name in field_names" py:with="field = fields[field_name]">
+ <option py:if="field.type in ('select', 'radio') or field_name in ('owner', 'reporter')"
+ selected="${field_name == query.group or None}"
+ value="${field_name}">${field.label}</option>
+ </py:for>
</select>
<input type="checkbox" name="groupdesc" id="groupdesc"
checked="${query.groupdesc or None}" />
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/templates/query_results.html
^
|
@@ -44,6 +44,11 @@
</thead>
<tbody>
+ <tr py:if="not results" class="even">
+ <td colspan="${len(headers)}">
+ No tickets found
+ </td>
+ </tr>
<py:for each="idx, result in enumerate(results)">
<py:with vars="ticket_context = context('ticket', result.id)">
<py:if test="'TICKET_VIEW' in perm(ticket_context.resource)">
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/templates/ticket.html
^
|
@@ -299,9 +299,10 @@
</td>
</tr>
</py:if>
- <tr py:for="row in group(fields, 2, lambda f: f.type != 'textarea')"
+ <tr py:for="row in group(fields, 2, lambda f: f.type != 'textarea' and f.name != 'owner')"
py:with="fullrow = len(row) == 1">
- <py:for each="idx, field in enumerate(row)">
+ <py:for each="idx, field in enumerate(row)"
+ py:with="value = ticket.get_value_or_default(field.name)">
<th class="col${idx + 1}" py:if="idx == 0 or not fullrow">
<label for="field-${field.name}" py:if="field"
py:strip="field.type == 'radio'">${field.edit_label or field.label or field.name}:</label>
@@ -312,27 +313,28 @@
<select py:when="'select'" id="field-${field.name}" name="field_${field.name}">
<option py:if="field.optional"></option>
<option py:for="option in field.options"
- selected="${ticket[field.name] == option or None}"
+ selected="${value == option or None}"
py:content="option"></option>
<optgroup py:for="optgroup in field.optgroups"
+ py:if="optgroup.options"
label="${optgroup.label}">
<option py:for="option in optgroup.options"
- selected="${ticket[field.name] == option or None}"
+ selected="${value == option or None}"
py:content="option"></option>
</optgroup>
</select>
<textarea py:when="'textarea'" id="field-${field.name}" name="field_${field.name}"
cols="${field.width}" rows="${field.height}"
- py:content="ticket[field.name]"></textarea>
+ py:content="value"></textarea>
<span py:when="'checkbox'">
<input type="checkbox" id="field-${field.name}" name="field_${field.name}"
- checked="${ticket[field.name] == '1' and 'checked' or None}" value="1" />
+ checked="${value == '1' and 'checked' or None}" value="1" />
<input type="hidden" name="field_checkbox_${field.name}" value="1" />
</span>
<label py:when="'radio'"
py:for="idx, option in enumerate(field.options)">
<input type="radio" name="field_${field.name}" value="${option}"
- checked="${ticket[field.name] == option or None}" />
+ checked="${value == option or None}" />
${option}
</label>
<py:otherwise><!--! Text input fields -->
@@ -347,11 +349,11 @@
<span py:when="field.name == 'cc'">
<input type="text" id="field-${field.name}"
title="Space or comma delimited email addresses and usernames are accepted."
- name="field_${field.name}" value="${ticket[field.name]}" />
+ name="field_${field.name}" value="${value}" />
</span>
<!--! All the other text input fields -->
<input py:otherwise="" type="text" id="field-${field.name}"
- name="field_${field.name}" value="${ticket[field.name]}" />
+ name="field_${field.name}" value="${value}" />
</py:choose>
</py:otherwise>
</py:choose>
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/tests/notification.py
^
|
@@ -415,7 +415,7 @@
"""MIME None/ascii encoding"""
self.env.config.set('notification','mime_encoding', 'none')
ticket = Ticket(self.env)
- ticket['reporter'] = 'joe.user@example.org'
+ ticket['reporter'] = 'joe.user'
ticket['summary'] = u'This is a summary'
ticket.insert()
self._validate_mimebody((None, '7bit', 'ascii'), \
@@ -609,7 +609,11 @@
# check banner content (field exists, msg value matches ticket value)
for p in [prop for prop in ticket.values.keys() if prop not in xlist]:
self.failIf(not props.has_key(p))
- self.failIf(props[p] != ticket[p])
+ # Email addresses might be obfuscated
+ if '@' in ticket[p] and '@' in props[p]:
+ self.failIf(props[p].split('@')[0] != ticket[p].split('@')[0])
+ else:
+ self.failIf(props[p] != ticket[p])
class NotificationTestSuite(unittest.TestSuite):
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/tests/query.py
^
|
@@ -137,7 +137,7 @@
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
LEFT OUTER JOIN milestone ON (milestone.name=milestone)
-ORDER BY COALESCE(t.milestone,'')='',COALESCE(milestone.due,0)=0,milestone.due,t.milestone,COALESCE(t.id,0)=0,t.id""")
+ORDER BY COALESCE(t.milestone,'')='',COALESCE(milestone.completed,0)=0,milestone.completed,COALESCE(milestone.due,0)=0,milestone.due,t.milestone,COALESCE(t.id,0)=0,t.id""")
self.assertEqual([], args)
tickets = query.execute(self.req)
@@ -149,7 +149,7 @@
FROM ticket AS t
LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
LEFT OUTER JOIN milestone ON (milestone.name=milestone)
-ORDER BY COALESCE(t.milestone,'')='' DESC,COALESCE(milestone.due,0)=0 DESC,milestone.due DESC,t.milestone DESC,COALESCE(t.id,0)=0,t.id""")
+ORDER BY COALESCE(t.milestone,'')='' DESC,COALESCE(milestone.completed,0)=0 DESC,milestone.completed DESC,COALESCE(milestone.due,0)=0 DESC,milestone.due DESC,t.milestone DESC,COALESCE(t.id,0)=0,t.id""")
self.assertEqual([], args)
tickets = query.execute(self.req)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/tests/roadmap.py
^
|
@@ -104,7 +104,7 @@
self.assertEquals('closed', closed['css_class'], 'closed class incorrect')
self.assertEquals(True, closed['overall_completion'],
'closed should contribute to overall completion')
- self.assertEquals({'status': ['closed'], 'group': 'resolution'},
+ self.assertEquals({'status': ['closed'], 'group': ['resolution']},
closed['qry_args'], 'qry_args incorrect')
self.assertEquals(1, closed['count'], 'closed count incorrect')
self.assertEquals(33, closed['percent'], 'closed percent incorrect')
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/tests/wikisyntax.py
^
|
@@ -14,7 +14,7 @@
------------------------------
<p>
<a class="new ticket" href="/ticket/1" title="This is the summary (new)">ticket:1</a>
-<a class="missing ticket" href="/ticket/12" rel="nofollow">ticket:12</a>
+<a class="missing ticket">ticket:12</a>
<a class="missing ticket">ticket:abc</a>
</p>
------------------------------
@@ -41,8 +41,8 @@
#12, #abc
------------------------------
<p>
-<a class="new ticket" href="/ticket/1" title="This is the summary (new)">#1</a>, <a class="missing ticket" href="/ticket/2" rel="nofollow">#2</a>
-<a class="missing ticket" href="/ticket/12" rel="nofollow">#12</a>, #abc
+<a class="new ticket" href="/ticket/1" title="This is the summary (new)">#1</a>, <a class="missing ticket">#2</a>
+<a class="missing ticket">#12</a>, #abc
</p>
------------------------------
============================== escaping the above
@@ -148,11 +148,11 @@
------------------------------
============================== milestone: link resolver + arguments
milestone:?action=new
-[milestone:1.0#KnownIssues Known Issues for 1.0]
+[milestone:boo#KnownIssues Known Issues for 1.0]
------------------------------
<p>
<a class="missing milestone" href="/milestone/?action=new" rel="nofollow">milestone:?action=new</a>
-<a class="missing milestone" href="/milestone/1.0#KnownIssues" rel="nofollow">Known Issues for 1.0</a>
+<a class="milestone" href="/milestone/boo#KnownIssues">Known Issues for 1.0</a>
</p>
------------------------------
""" #"
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/ticket/web_ui.py
^
|
@@ -107,9 +107,13 @@
"""Don't accept tickets with a too big description.
(''since 0.11'').""")
+ max_comment_size = IntOption('ticket', 'max_comment_size', 262144,
+ """Don't accept tickets with a too big comment.
+ (''since 0.11.2'')""")
+
timeline_newticket_formatter = Option('timeline', 'newticket_formatter',
'oneliner',
- """Which formatter flavor (e.g. 'default' or 'oneliner') should be
+ """Which formatter flavor (e.g. 'html' or 'oneliner') should be
used when presenting the description for new tickets.
If 'oneliner', the [timeline] abbreviated_messages option applies.
(''since 0.11'').""")
@@ -121,6 +125,13 @@
but keeps the old behavior for upgraded environments (i.e. 'no').
(''since 0.11'').""")
+ def _must_preserve_newlines(self):
+ preserve_newlines = self.preserve_newlines
+ if preserve_newlines == 'default':
+ preserve_newlines = self.env.get_version(initial=True) >= 21 # 0.11
+ return preserve_newlines in _TRUE_VALUES
+ must_preserve_newlines = property(_must_preserve_newlines)
+
# IContentConverter methods
def get_supported_conversions(self):
@@ -156,7 +167,7 @@
# IRequestHandler methods
def match_request(self, req):
- if re.match(r'/newticket/?$', req.path_info) is not None:
+ if req.path_info == "/newticket":
return True
match = re.match(r'/ticket/([0-9]+)$', req.path_info)
if match:
@@ -165,7 +176,7 @@
def process_request(self, req):
if 'id' in req.args:
- if req.path_info.startswith('/newticket'):
+ if req.path_info == '/newticket':
raise TracError(_("id can't be set for a new ticket request."))
return self._process_ticket_request(req)
return self._process_newticket_request(req)
@@ -193,13 +204,15 @@
sql2, args2 = search_to_sql(db, ['summary', 'keywords', 'description',
'reporter', 'cc',
db.cast('id', 'text')], terms)
+ sql3, args3 = search_to_sql(db, ['c.value'], terms)
cursor = db.cursor()
cursor.execute("SELECT DISTINCT a.summary,a.description,a.reporter, "
"a.type,a.id,a.time,a.status,a.resolution "
"FROM ticket a "
"LEFT JOIN ticket_change b ON a.id = b.ticket "
- "WHERE (b.field='comment' AND %s ) OR %s" % (sql, sql2),
- args + args2)
+ "LEFT OUTER JOIN ticket_custom c ON (a.id = c.ticket) "
+ "WHERE (b.field='comment' AND %s) OR %s OR %s" %
+ (sql, sql2, sql3), args + args2 + args3)
ticketsystem = TicketSystem(self.env)
for summary, desc, author, type, tid, ts, status, resolution in cursor:
t = ticket_realm(id=tid)
@@ -333,17 +346,17 @@
descr = message = ''
if status == 'new':
message = description
- flavor = self.timeline_newticket_formatter
else:
descr = info
message = comment
- flavor = 'oneliner'
- if message:
- if self.config['timeline'].getbool('abbreviated_messages'):
- message = shorten_line(message)
- descr += format_to(self.env, flavor, context(resource=ticket),
- message)
- return descr
+ t_context = context(resource=ticket)
+ t_context.set_hints(preserve_newlines=self.must_preserve_newlines)
+ if status == 'new' and \
+ context.get_hint('wiki_flavor') == 'oneliner':
+ flavor = self.timeline_newticket_formatter
+ t_context.set_hints(wiki_flavor=flavor,
+ shorten_lines=flavor == 'oneliner')
+ return descr + format_to(self.env, None, t_context, message)
# Internal methods
@@ -521,7 +534,7 @@
if format:
# FIXME: mime.send_converted(context, ticket, 'ticket_x')
mime.send_converted(req, 'trac.ticket.Ticket', ticket,
- format, 'ticket_%d' % ticket.id)
+ format, filename=None)
def add_ticket_link(css_class, id):
t = ticket.resource(id=id, version=None)
@@ -572,14 +585,10 @@
return 'ticket.html', data, None
def _prepare_data(self, req, ticket, absurls=False):
- preserve_newlines = self.preserve_newlines
- if preserve_newlines == 'default':
- preserve_newlines = self.env.get_version(initial=True) >= 21 # 0.11
- preserve_newlines = preserve_newlines in _TRUE_VALUES
return {'ticket': ticket,
'context': Context.from_request(req, ticket.resource,
absurls=absurls),
- 'preserve_newlines': preserve_newlines}
+ 'preserve_newlines': self.must_preserve_newlines}
def _toggle_cc(self, req, cc):
"""Return an (action, recipient) tuple corresponding to a change
@@ -928,6 +937,13 @@
num=self.max_description_size))
valid = False
+ # Validate comment length
+ if len(comment or '') > self.max_comment_size:
+ add_warning(req, _('Ticket comment is too long (must be less '
+ 'than %(num)s characters)',
+ num=self.max_comment_size))
+ valid = False
+
# Validate comment numbering
try:
# comment index must be a number
@@ -1051,6 +1067,7 @@
def _prepare_fields(self, req, ticket):
context = Context.from_request(req, ticket.resource)
fields = []
+ owner_field = None
for field in ticket.fields:
name = field['name']
type_ = field['type']
@@ -1060,11 +1077,14 @@
'resolution'):
field['skip'] = True
elif name == 'owner':
+ TicketSystem(self.env).eventually_restrict_owner(field, ticket)
+ type_ = field['type']
field['skip'] = True
if not ticket.exists:
field['label'] = 'Assign to'
if 'TICKET_MODIFY' in req.perm(ticket.resource):
field['skip'] = False
+ owner_field = field
elif name == 'milestone':
milestones = [(opt, Milestone(self.env, opt))
for opt in field['options']]
@@ -1127,6 +1147,11 @@
field.setdefault('options', [])
field.setdefault('skip', False)
fields.append(field)
+
+ # Move owner field to end when shown
+ if owner_field is not None:
+ fields.remove(owner_field)
+ fields.append(owner_field)
return fields
def _insert_ticket_data(self, req, ticket, data, author_id, field_changes):
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/timeline/web_ui.py
^
|
@@ -58,7 +58,7 @@
Timeline. (''since 0.11'')""")
abbreviated_messages = BoolOption('timeline', 'abbreviated_messages',
- 'true',
+ True,
"""Whether wiki-formatted event messages should be truncated or not.
This only affects the default rendering, and can be overriden by
@@ -83,7 +83,7 @@
# IRequestHandler methods
def match_request(self, req):
- return re.match(r'/timeline/?', req.path_info) is not None
+ return req.path_info == '/timeline'
def process_request(self, req):
req.perm.assert_permission('TIMELINE_VIEW')
@@ -101,9 +101,9 @@
precision = req.args.get('precision', '')
if precision.startswith('second'):
precision = timedelta(seconds=1)
- elif precision.startswith('minutes'):
+ elif precision.startswith('minute'):
precision = timedelta(minutes=1)
- elif precision.startswith('hours'):
+ elif precision.startswith('hour'):
precision = timedelta(hours=1)
else:
precision = None
@@ -179,10 +179,16 @@
if email:
email_map[username] = email
data['email_map'] = email_map
- data['context'] = Context.from_request(req, absurls=True)
+ rss_context = Context.from_request(req, absurls=True)
+ rss_context.set_hints(wiki_flavor='html', shorten_lines=False)
+ data['context'] = rss_context
return 'timeline.rss', data, 'application/rss+xml'
else:
req.session['timeline.daysback'] = daysback
+ html_context = Context.from_request(req, absurls=True)
+ html_context.set_hints(wiki_flavor='oneliner',
+ shorten_lines=self.abbreviated_messages)
+ data['context'] = html_context
add_stylesheet(req, 'common/css/timeline.css')
rss_href = req.href.timeline([(f, 'on') for f in filters],
@@ -284,8 +290,8 @@
kind, date, author, data, provider = event
else:
kind, date, author, data = event
- render = lambda field, context: provider.render_timeline_event(
- context, field, event)
+ render = lambda field, context: \
+ provider.render_timeline_event(context, field, event)
if isinstance(date, datetime):
dateuid = to_timestamp(date)
else:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/util/daemon.py
^
|
@@ -14,6 +14,7 @@
import atexit
import errno
import os
+import signal
import sys
def daemonize(pidfile=None, progname=None, stdin='/dev/null',
@@ -69,14 +70,23 @@
os.dup2(stderr.fileno(), sys.stderr.fileno())
if pidfile:
+ # Register signal handlers to ensure atexit hooks are called on exit
+ for signum in [signal.SIGTERM, signal.SIGHUP]:
+ signal.signal(signum, handle_signal)
+
# Create/update the pid file, and register a hook to remove it when the
# process exits
+ def remove_pidfile():
+ if os.path.exists(pidfile):
+ os.remove(pidfile)
+ atexit.register(remove_pidfile)
fileobj = open(pidfile, 'w')
try:
fileobj.write(str(os.getpid()))
finally:
fileobj.close()
- def remove_pidfile():
- if os.path.exists(pidfile):
- os.remove(pidfile)
- atexit.register(remove_pidfile)
+
+
+def handle_signal(signum, frame):
+ """Handle signals sent to the daemonized process."""
+ sys.exit()
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/util/html.py
^
|
@@ -14,10 +14,76 @@
import re
from genshi import Markup, escape, unescape
-from genshi.core import stripentities, striptags
+from genshi.core import stripentities, striptags, START, END
from genshi.builder import Element, ElementFactory, Fragment
+from genshi.filters.html import HTMLSanitizer
-__all__ = ['escape', 'unescape', 'html', 'plaintext']
+from trac.util.compat import set
+
+__all__ = ['escape', 'unescape', 'html', 'plaintext', 'TracHTMLSanitizer']
+
+
+class TracHTMLSanitizer(HTMLSanitizer):
+
+ UNSAFE_CSS = ['position']
+
+ def __init__(self):
+ safe_attrs = HTMLSanitizer.SAFE_ATTRS | set(['style'])
+ super(TracHTMLSanitizer, self).__init__(safe_attrs=safe_attrs)
+
+ def sanitize_css(self, text):
+ decls = []
+ text = self._strip_css_comments(self._replace_unicode_escapes(text))
+ for decl in filter(None, text.split(';')):
+ decl = decl.strip()
+ if not decl:
+ continue
+ try:
+ prop, value = decl.split(':', 1)
+ except ValueError:
+ continue
+ if not self.is_safe_css(prop.strip().lower(), value.strip()):
+ continue
+ is_evil = False
+ if 'expression' in decl:
+ is_evil = True
+ for match in re.finditer(r'url\s*\(([^)]+)', decl):
+ if not self.is_safe_uri(match.group(1)):
+ is_evil = True
+ break
+ if not is_evil:
+ decls.append(decl.strip())
+ return decls
+
+ def __call__(self, stream):
+ """Remove input type="password" elements from the stream
+ """
+ suppress = False
+ for kind, data, pos in super(TracHTMLSanitizer, self).__call__(stream):
+ if kind is START:
+ tag, attrs = data
+ if (tag == 'input' and
+ attrs.get('type', '').lower() == 'password'):
+ suppress = True
+ else:
+ yield kind, data, pos
+ elif kind is END:
+ if not suppress:
+ yield kind, data, pos
+ suppress = False
+ else:
+ yield kind, data, pos
+
+ def is_safe_css(self, prop, value):
+ """Determine whether the given css property declaration is to be
+ considered safe for inclusion in the output.
+ """
+ if prop in self.UNSAFE_CSS:
+ return False
+ # Negative margins can be used for phishing
+ elif prop.startswith('margin') and '-' in value:
+ return False
+ return True
class Deuglifier(object):
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/util/text.py
^
|
@@ -161,10 +161,10 @@
def shorten_line(text, maxlen=75):
if len(text or '') < maxlen:
return text
- shortline = text[:maxlen]
- cut = shortline.rfind(' ') + 1 or shortline.rfind('\n') + 1 or maxlen
- shortline = text[:cut]+' ...'
- return shortline
+ cut = max(text.rfind(' ', 0, maxlen), text.rfind('\n', 0, maxlen))
+ if cut < 0:
+ cut = maxlen
+ return text[:cut] + ' ...'
def wrap(t, cols=75, initial_indent='', subsequent_indent='',
linesep=os.linesep):
@@ -201,7 +201,7 @@
if size < jump:
return '%d bytes' % size
- units = ['kB', 'MB', 'GB', 'TB']
+ units = ['KB', 'MB', 'GB', 'TB']
i = 0
while size >= jump and i < len(units):
i += 1
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/versioncontrol/api.py
^
|
@@ -139,7 +139,7 @@
raise TracError(
_('Unsupported version control system "%(name)s"'
': "%(error)s" ', name=self.repository_type,
- error=connector.error))
+ error=to_unicode(connector.error)))
self._connector = connector
else:
raise TracError(
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/versioncontrol/templates/browser.html
^
|
@@ -93,6 +93,11 @@
</tr>
</py:if>
<xi:include href="dir_entries.html" />
+ <tr py:if="'up' not in chrome.links and not dir.entries" class="even">
+ <td class="name" colspan="5">
+ No files found
+ </td>
+ </tr>
</tbody>
</table>
</py:if>
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/versioncontrol/templates/revisionlog.html
^
|
@@ -97,6 +97,14 @@
</tr>
</thead>
<tbody>
+ <tr py:if="not items" class="even">
+ <td />
+ <td />
+ <td class="copyfrom_path" colspan="6">
+ No revisions found
+ </td>
+ </tr>
+
<py:for each="idx, item in enumerate(items)">
<py:with vars="change = changes[item.rev];
chgset_context = context('changeset', change.rev);
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/versioncontrol/web_ui/browser.py
^
|
@@ -235,14 +235,14 @@
render_unsafe_content = BoolOption('browser', 'render_unsafe_content',
'false',
- """Whether attachments should be rendered in the browser, or
- only made downloadable.
+ """Whether raw files should be rendered in the browser, or only made
+ downloadable.
Pretty much any file may be interpreted as HTML by the browser,
- which allows a malicious user to attach a file containing cross-site
+ which allows a malicious user to create a file containing cross-site
scripting attacks.
- For public sites where anonymous users can create attachments it is
+ For open repositories where anyone can check-in a file, it is
recommended to leave this option disabled (which is the default).""")
# public methods
@@ -304,8 +304,7 @@
# IRequestHandler methods
def match_request(self, req):
- import re
- match = re.match(r'/(export|browser|file)(?:(/.*))?', req.path_info)
+ match = re.match(r'/(export|browser|file)(/.*)?$', req.path_info)
if match:
mode, path = match.groups()
if mode == 'export':
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/versioncontrol/web_ui/changeset.py
^
|
@@ -47,7 +47,7 @@
from trac.web.chrome import add_ctxtnav, add_link, add_script, add_stylesheet, \
prevnext_nav, INavigationContributor, Chrome
from trac.wiki import IWikiSyntaxProvider, WikiParser
-from trac.wiki.formatter import format_to_html
+from trac.wiki.formatter import format_to
class IPropertyDiffRenderer(Interface):
@@ -178,7 +178,7 @@
# IRequestHandler methods
- _request_re = re.compile(r"/changeset(?:/([^/]+))?(/.*)?$")
+ _request_re = re.compile(r"/changeset(?:/([^/]+)(/.*)?)?$")
def match_request(self, req):
match = re.match(self._request_re, req.path_info)
@@ -824,10 +824,12 @@
return context.href.log(rev=rev_b, stop_rev=rev_a)
elif field == 'description':
- if not self.timeline_long_messages:
- message = shorten_line(message)
if self.wiki_format_messages:
markup = ''
+ if self.timeline_long_messages: # override default flavor
+ context = context()
+ context.set_hints(wiki_flavor='html',
+ preserve_newlines=True)
else:
markup = message
message = None
@@ -861,7 +863,7 @@
files = files[:show_files] + [tag.li(u'\u2026')]
markup = tag(tag.ul(files, class_="changes"), markup)
if message:
- markup += format_to_html(self.env, context, message)
+ markup += format_to(self.env, None, context, message)
return markup
if rev_a == rev_b:
@@ -908,16 +910,17 @@
rev, path = chgset[:sep], chgset[sep:]
else:
rev, path = chgset, None
- try:
- changeset = self.env.get_repository().get_changeset(rev)
- return tag.a(label, class_="changeset",
- title=shorten_line(changeset.message),
- href=(formatter.href.changeset(rev, path) +
- params + fragment))
- except TracError, e:
- return tag.a(label, class_="missing changeset",
- href=formatter.href.changeset(rev, path),
- title=unicode(e), rel="nofollow")
+ if 'CHANGESET_VIEW' in formatter.perm('changeset', rev):
+ try:
+ changeset = self.env.get_repository().get_changeset(rev)
+ return tag.a(label, class_="changeset",
+ title=shorten_line(changeset.message),
+ href=(formatter.href.changeset(rev, path) +
+ params + fragment))
+ except TracError, e:
+ return tag.a(label, class_="missing changeset",
+ title=unicode(e))
+ return tag.a(label, class_="missing changeset")
def _format_diff_link(self, formatter, ns, target, label):
params, query, fragment = formatter.split_link(target)
@@ -980,7 +983,7 @@
# IRequestHandler methods
def match_request(self, req):
- return re.match(r'/diff$', req.path_info)
+ return req.path_info == '/diff'
def process_request(self, req):
repos = self.env.get_repository(req.authname)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/versioncontrol/web_ui/log.py
^
|
@@ -64,8 +64,7 @@
# IRequestHandler methods
def match_request(self, req):
- import re
- match = re.match(r'/log(?:(/.*)|$)', req.path_info)
+ match = re.match(r'/log(/.*)?$', req.path_info)
if match:
req.args['path'] = match.group(1) or '/'
return True
@@ -305,7 +304,10 @@
if revs and query:
query = '&' + query[1:]
href = formatter.href.log(path or '/', revs=revs) + query + fragment
- return html.A(label, class_='source', href=href)
+ if 'LOG_VIEW' in formatter.perm:
+ return html.A(label, class_='source', href=href)
+ else:
+ return html.A(label, class_='missing source')
LOG_LINK_RE = re.compile(r"([^@:]*)[@:]%s?" % REV_RANGE)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/versioncontrol/web_ui/tests/wikisyntax.py
^
|
@@ -38,8 +38,8 @@
------------------------------
<p>
<a class="changeset" href="/changeset/1" title="start">changeset:1</a>
-<a class="missing changeset" href="/changeset/12" rel="nofollow" title="No changeset 12 in the repository">changeset:12</a>
-<a class="missing changeset" href="/changeset/abc" rel="nofollow" title="No changeset abc in the repository">changeset:abc</a>
+<a class="missing changeset" title="No changeset 12 in the repository">changeset:12</a>
+<a class="missing changeset" title="No changeset abc in the repository">changeset:abc</a>
<a class="changeset" href="/changeset/1" title="start">changeset:1</a>, <a class="changeset" href="/changeset/1/README.txt" title="start">changeset:1/README.txt</a>
</p>
------------------------------
@@ -59,7 +59,7 @@
------------------------------
<p>
<a class="changeset" href="/changeset/1" title="start">[1]</a>, <a class="changeset" href="/changeset/1" title="start">r1</a>
-<a class="missing changeset" href="/changeset/12" rel="nofollow" title="No changeset 12 in the repository">[12]</a>, <a class="missing changeset" href="/changeset/12" rel="nofollow" title="No changeset 12 in the repository">r12</a>, rABC
+<a class="missing changeset" title="No changeset 12 in the repository">[12]</a>, <a class="missing changeset" title="No changeset 12 in the repository">r12</a>, rABC
<a class="changeset" href="/changeset/1/README.txt" title="start">[1/README.txt]</a>
</p>
------------------------------
@@ -90,13 +90,13 @@
rfc and rfc:4180 should not be changeset links, neither should rfc4180
------------------------------
<p>
-Change:<a class="missing changeset" href="/changeset/10" rel="nofollow" title="No changeset 10 in the repository">[10]</a> There should be a link to changeset <a class="missing changeset" href="/changeset/10" rel="nofollow" title="No changeset 10 in the repository">[10]</a>
+Change:<a class="missing changeset" title="No changeset 10 in the repository">[10]</a> There should be a link to changeset <a class="missing changeset" title="No changeset 10 in the repository">[10]</a>
</p>
<p>
rfc and rfc:4180 should not be changeset links, neither should rfc4180
</p>
------------------------------
-Change:<a class="missing changeset" href="/changeset/10" rel="nofollow" title="No changeset 10 in the repository">[10]</a> There should be a link to changeset <a class="missing changeset" href="/changeset/10" rel="nofollow" title="No changeset 10 in the repository">[10]</a>
+Change:<a class="missing changeset" title="No changeset 10 in the repository">[10]</a> There should be a link to changeset <a class="missing changeset" title="No changeset 10 in the repository">[10]</a>
rfc and rfc:4180 should not be changeset links, neither should rfc4180
============================== InterTrac for changesets
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/web/api.py
^
|
@@ -26,7 +26,7 @@
import urlparse
from trac.core import Interface, TracError
-from trac.util import get_last_traceback, md5
+from trac.util import get_last_traceback, md5, unquote
from trac.util.datefmt import http_date, localtz
from trac.web.href import Href
from trac.web.wsgi import _FileWrapper
@@ -99,6 +99,31 @@
return val
+def parse_query_string(query_string):
+ """Parse a query string into a _RequestArgs."""
+ args = _RequestArgs()
+ for arg in query_string.split('&'):
+ nv = arg.split('=', 1)
+ if len(nv) == 2:
+ (name, value) = nv
+ else:
+ (name, value) = (nv[0], '')
+ name = unquote(name.replace('+', ' '))
+ if isinstance(name, unicode):
+ name = name.encode('utf-8')
+ value = unquote(value.replace('+', ' '))
+ if not isinstance(value, unicode):
+ value = unicode(value, 'utf-8')
+ if name in args:
+ if isinstance(args[name], list):
+ args[name].append(value)
+ else:
+ args[name] = [args[name], value]
+ else:
+ args[name] = value
+ return args
+
+
class RequestDone(Exception):
"""Marker exception that indicates whether request processing has completed
and a response was sent.
@@ -181,6 +206,9 @@
doc='The HTTP method of the request')
path_info = property(fget=lambda self: self.environ.get('PATH_INFO', '').decode('utf-8'),
doc='Path inside the application')
+ query_string = property(fget=lambda self: self.environ.get('QUERY_STRING',
+ ''),
+ doc='Query part of the request')
remote_addr = property(fget=lambda self: self.environ.get('REMOTE_ADDR'),
doc='IP address of the remote user')
remote_user = property(fget=lambda self: self.environ.get('REMOTE_USER'),
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/web/auth.py
^
|
@@ -52,7 +52,7 @@
implements(IAuthenticator, INavigationContributor, IRequestHandler)
- check_ip = BoolOption('trac', 'check_auth_ip', 'true',
+ check_ip = BoolOption('trac', 'check_auth_ip', 'false',
"""Whether the IP address of the user should be checked for
authentication (''since 0.9'').""")
@@ -144,6 +144,8 @@
req.authname = remote_user
req.outcookie['trac_auth'] = cookie
req.outcookie['trac_auth']['path'] = req.base_path or '/'
+ if self.env.secure_cookies:
+ req.outcookie['trac_auth']['secure'] = True
def _do_logout(self, req):
"""Log the user out.
@@ -175,6 +177,8 @@
req.outcookie['trac_auth'] = ''
req.outcookie['trac_auth']['path'] = req.base_path or '/'
req.outcookie['trac_auth']['expires'] = -10000
+ if self.env.secure_cookies:
+ req.outcookie['trac_auth']['secure'] = True
def _get_name_for_cookie(self, req, cookie):
db = self.env.get_db_cnx()
@@ -197,13 +201,16 @@
def _redirect_back(self, req):
"""Redirect the user back to the URL she came from."""
- referer = req.get_header('Referer')
+ referer = self._referer(req)
if referer and not (referer == req.base_url or \
referer.startswith(req.base_url.rstrip('/')+'/')):
# only redirect to referer if it is from the same site
referer = None
req.redirect(referer or req.abs_href())
+ def _referer(self, req):
+ return req.args.get('referer') or req.get_header('Referer')
+
class HTTPAuthentication(object):
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/web/chrome.py
^
|
@@ -113,12 +113,16 @@
def add_warning(req, msg, *args):
"""Add a non-fatal warning to the request object.
When rendering pages, any warnings will be rendered to the user."""
- req.chrome['warnings'].append(msg % args)
+ if args:
+ msg %= args
+ req.chrome['warnings'].append(msg)
def add_notice(req, msg, *args):
"""Add an informational notice to the request object.
When rendering pages, any notice will be rendered to the user."""
- req.chrome['notices'].append(msg % args)
+ if args:
+ msg %= args
+ req.chrome['notices'].append(msg)
def add_ctxtnav(req, elm_or_label, href=None, title=None):
"""Add an entry to the current page's ctxtnav bar.
@@ -468,7 +472,7 @@
href = category_section.get(name + '.href')
if href:
if href.startswith('/'):
- href = req.href(href)
+ href = req.href() + href
if label:
item = tag.a(label) # create new label
elif not item:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/web/href.py
^
|
@@ -129,7 +129,7 @@
if type(value) in (list, tuple):
for i in [i for i in value if i != None]:
params.append((name, i))
- elif v != None:
+ elif value != None:
params.append((name, value))
if args:
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/web/main.py
^
|
@@ -43,6 +43,7 @@
from trac.util.compat import partial, reversed
from trac.util.datefmt import format_datetime, http_date, localtz, timezone
from trac.util.text import shorten_line, to_unicode
+from trac.util.translation import _
from trac.web.api import *
from trac.web.chrome import Chrome
from trac.web.clearsilver import HDFWrapper
@@ -174,6 +175,12 @@
except TracError, e:
raise HTTPInternalError(e)
if not chosen_handler:
+ if req.path_info.endswith('/'):
+ # Strip trailing / and redirect
+ target = req.path_info.rstrip('/').encode('utf-8')
+ if req.query_string:
+ target += '?' + req.query_string
+ req.redirect(req.href() + target, permanent=True)
raise HTTPNotFound('No handler matched request to %s',
req.path_info)
@@ -279,6 +286,8 @@
else:
req.outcookie['trac_form_token'] = hex_entropy(24)
req.outcookie['trac_form_token']['path'] = req.base_path or '/'
+ if self.env.secure_cookies:
+ req.outcookie['trac_form_token']['secure'] = True
return req.outcookie['trac_form_token'].value
def _pre_process_request(self, req, chosen_handler):
@@ -436,6 +445,11 @@
title = 'Error: %s' % e.reason
data = {'title': title, 'type': 'TracError', 'message': e.detail,
'frames': [], 'traceback': None}
+ if e.code == 403 and req.authname == 'anonymous':
+ req.chrome['notices'].append(Markup(
+ _('You are currently not logged in. You may want to '
+ '<a href="%(href)s">do so</a> now.',
+ href=req.href.login())))
try:
req.send_error(sys.exc_info(), status=e.code, env=env, data=data)
except RequestDone:
@@ -511,11 +525,6 @@
data[key] = val
if use_clearsilver:
req.hdf[key] = val
-
- if parent_dir and not env_paths:
- env_paths = dict([(filename, os.path.join(parent_dir, filename))
- for filename in os.listdir(parent_dir)])
-
try:
href = Href(req.base_path)
projects = []
@@ -560,7 +569,8 @@
paths = dircache.listdir(env_parent_dir)[:]
dircache.annotate(env_parent_dir, paths)
env_paths += [os.path.join(env_parent_dir, project) \
- for project in paths if project[-1] == '/']
+ for project in paths
+ if project[-1] == '/' and project != '.egg-cache/']
envs = {}
for env_path in env_paths:
env_path = os.path.normpath(env_path)
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/web/session.py
^
|
@@ -97,9 +97,16 @@
(self.sid,))
self._old = dict(self.items())
if attrs:
- cursor.executemany("INSERT INTO session_attribute "
- "(sid,authenticated,name,value) "
- "VALUES(%s,%s,%s,%s)", attrs)
+ # The session variables might already have been updated by a
+ # concurrent request.
+ try:
+ cursor.executemany("INSERT INTO session_attribute "
+ "(sid,authenticated,name,value) "
+ "VALUES(%s,%s,%s,%s)", attrs)
+ except Exception, e:
+ db.rollback()
+ self.env.log.warning('Attributes for session %s already '
+ 'updated: %s' % (self.sid, e))
elif not authenticated:
# No need to keep around empty unauthenticated sessions
cursor.execute("DELETE FROM session "
@@ -154,6 +161,8 @@
self.req.outcookie[COOKIE_KEY] = self.sid
self.req.outcookie[COOKIE_KEY]['path'] = self.req.base_path or '/'
self.req.outcookie[COOKIE_KEY]['expires'] = expires
+ if self.env.secure_cookies:
+ self.req.outcookie[COOKIE_KEY]['secure'] = True
def get_session(self, sid, authenticated=False):
refresh_cookie = False
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/web/tests/auth.py
^
|
@@ -42,7 +42,8 @@
self.assertEqual('john', self.module.authenticate(req))
self.failIf('auth_cookie' in req.outcookie)
- def test_known_cookie_different_ipnr_access(self):
+ def test_known_cookie_ip_check_enabled(self):
+ self.env.config.set('trac', 'check_auth_ip', 'yes')
cursor = self.db.cursor()
cursor.execute("INSERT INTO auth_cookie (cookie, name, ipnr) "
"VALUES ('123', 'john', '127.0.0.1')")
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/api.py
^
|
@@ -316,13 +316,16 @@
else:
if ignore_missing:
return label
- return tag.a(label+'?', href=href, class_='missing wiki',
- rel='nofollow')
+ if 'WIKI_CREATE' in formatter.perm('wiki', pagename, version):
+ return tag.a(label + '?', class_='missing wiki',
+ href=href, rel='nofollow')
+ else:
+ return tag.a(label + '?', class_='missing wiki')
elif ignore_missing and not self.has_page(pagename):
return label
else:
- return tag.span(label, class_='forbidden wiki',
- title=_("no permission to view this wiki page"))
+ return tag.a(label, class_='forbidden wiki',
+ title=_("no permission to view this wiki page"))
# IResourceManager methods
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/InterTrac
^
|
@@ -60,8 +60,8 @@
Finally, the `.compat` option can be used to activate or disable
a ''compatibility'' mode:
- * If the targeted Trac is running a version below milestone:0.10
- (r3526 to be precise), then it doesn't know how to dispatch an InterTrac
+ * If the targeted Trac is running a version below [trac:milestone:0.10 0.10]
+ ([trac:r3526 r3526] to be precise), then it doesn't know how to dispatch an InterTrac
link, and it's up to the local Trac to prepare the correct link.
Not all links will work that way, but the most common do.
This is called the compatibility mode, and is `true` by default.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/InterWiki
^
|
@@ -1,6 +1,6 @@
= Support for InterWiki links =
-''(since [milestone:0.10])''
+''(since [trac:milestone:0.10 0.10])''
== Definition ==
@@ -10,7 +10,7 @@
mapping can be done.
At the extreme, InterWiki prefixes can even be used to simply introduce
-links to new protocols, such as `tsvn:` used by TortoiseSvn.
+links to new protocols, such as `tsvn:` used by [trac:TortoiseSvn TortoiseSvn].
== Link Syntax ==
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracAdmin
^
|
@@ -43,5 +43,8 @@
The `initenv` also supports an extra `--inherit` option, which can be used to specify the `[inherit] file` option at environment creation time so that only the options ''not'' already specified in the global configuration file will be written in the conf/trac.ini file of the newly created environment.
See TracIni#GlobalConfiguration.
+
+Note that in version 0.11 of Trac, `initenv` lost an extra last argument `<templatepath>`, which was used in previous versions to point to the `templates` folder. If you are using the one-liner '`trac-admin /path/to/trac/ initenv <projectname> <db> <repostype> <repospath>`' in the above and getting an error that reads ''''`Wrong number of arguments to initenv: 4`'''', then this is because you're using a `trac-admin` script from an '''older''' version of Trac.
+
----
-See also: TracGuide, TracBackup, TracPermissions, TracEnvironment, TracIni, TracMigrate
+See also: TracGuide, TracBackup, TracPermissions, TracEnvironment, TracIni, [trac:TracMigrate TracMigrate]
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracBrowser
^
|
@@ -33,8 +33,9 @@
If you're using a Javascript enabled brower, you'll be able to expand and collapse folders in-place by clicking on the arrow head at the right side of a folder. Alternatively, the keyboard can also be used for this: use 'j' and 'k' to go to the next or previous entry, and 'o' (or 'Enter') to toggle between expanded and collapsed state of the selected folder or for visiting the selected file.
For the Subversion backend, some additional features are available:
- - support for `svn:needs-lock` property
- - support for `svn:externals` property (which can be [TracIni#svn:externals-section configured])
+ - Support for the `svn:needs-lock` property
+ - Support for the `svn:externals` property (which can be [TracIni#svn:externals-section configured])
+ - The `svn:mime-type` property is used to select the syntax highlighter for rendering the file. For example, setting `svn:mime-type` to `text/html` will ensure the file is highlighted as HTML, regardless of the file extension. It also allows selecting the character encoding used in the file content. For example, if the file content is encoded in UTF-8, set `svn:mime-type` to `text/html;charset=utf-8`. The `charset=` specification overrides the default encoding defined in the `default_charset` option of the `[trac]` section of [TracIni#trac-section trac.ini].
----
See also: TracGuide, TracChangeset, TracFineGrainedPermissions
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracCgi
^
|
@@ -2,12 +2,15 @@
To install Trac as a CGI script, you need to make the `trac.cgi` executable as a CGI by your web server.
- ''Please note that using Trac via CGI is significantly slower than any other deployment method, such as [TracModPython mod_python] or [TracFastCgi FastCGI].''
+{{{
+#!div class=important
+ ''Please note that using Trac via CGI is significantly slower than any other deployment method, such as [TracModPython mod_python] or [TracFastCgi FastCGI] or even [trac:TracOnWindowsIisAjp IIS/AJP] on Windows.''
+}}}
If you're using [http://httpd.apache.org/ Apache HTTPD], there are a couple ways to do that:
1. Use a `ScriptAlias` to map a URL to the `trac.cgi` script
- 2. Copy the `trac.cgi` file into the directory for CGI executables used by your web server (commonly named `cgi-bin`). You can also create a symbolic link, but in that case make sure that the `FollowSymLinks` option is enabled for the `cgi-bin` directory.
+ 2. Copy the `trac.cgi` file into the directory for CGI executables used by your web server (commonly named `cgi-bin`). A word of warning, copying the file directly from the repository onto a windows server 2003 machine created difficulties. Rather create a new text file and cut and copy the text into the newly created file. You can also create a symbolic link, but in that case make sure that the `FollowSymLinks` option is enabled for the `cgi-bin` directory.
The first option is recommended as it also allows you to map the CGI to a friendly URL.
@@ -138,14 +141,14 @@
</LocationMatch>
}}}
-For better security, it is recommended that you either enable SSL or at least use the “Digest” authentication scheme instead of “Basic”. Please read the [http://httpd.apache.org/docs/2.0/ Apache HTTPD documentation] to find out more. For example, on a Debian 4.0r1 (etch) system the relevant section in apache configuration can look like this:
+For better security, it is recommended that you either enable SSL or at least use the “digest” authentication scheme instead of “Basic”. Please read the [http://httpd.apache.org/docs/2.0/ Apache HTTPD documentation] to find out more. For example, on a Debian 4.0r1 (etch) system the relevant section in apache configuration can look like this:
{{{
<Location "/trac/login">
LoadModule auth_digest_module /usr/lib/apache2/modules/mod_auth_digest.so
AuthType Digest
AuthName "trac"
AuthDigestDomain /trac
- AuthDigestFile /somewhere/trac.htpasswd
+ AuthUserFile /somewhere/trac.htpasswd
Require valid-user
</Location>
}}}
@@ -156,4 +159,4 @@
where the "trac" parameter above is the same as !AuthName above ("Realm" in apache-docs).
----
-See also: TracGuide, TracInstall, TracFastCgi, TracModPython
+See also: TracGuide, TracInstall, TracFastCgi, TracModPython
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracEnvironment
^
|
@@ -132,8 +132,8 @@
* `trac.db` - The SQLite database (if you're using SQLite).
* `htdocs` - directory containing web resources, which can be referenced in Genshi templates. '''''(0.11 only)'''''
* `log` - default directory for log files, if logging is turned on and a relative path is given.
- * `plugins` - Environment-specific [wiki:TracPlugins plugins] (Python eggs, since [milestone:0.10])
- * `templates` - Custom ClearSilver environment-specific templates. '''''(0.10 only)'''''
+ * `plugins` - Environment-specific [wiki:TracPlugins plugins] (Python eggs, since [trac:milestone:0.10 0.10])
+ * `templates` - Custom [trac:ClearSilver ClearSilver] environment-specific templates. '''''(0.10 only)'''''
* `site_css.cs` - Custom CSS rules.
* `site_footer.cs` - Custom page footer.
* `site_header.cs` - Custom page header.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracFastCgi
^
|
@@ -2,12 +2,7 @@
Since version 0.9, Trac supports being run through the [http://www.fastcgi.com/ FastCGI] interface. Like [wiki:TracModPython mod_python], this allows Trac to remain resident, and is faster than external CGI interfaces which must start a new process for each request. However, unlike mod_python, it is able to support [http://httpd.apache.org/docs/suexec.html SuEXEC]. Additionally, it is supported by much wider variety of web servers.
-{{{
-#!html
-<p style="background: #fdc; border: 2px solid #d00; font-style: italic; padding: 0 .5em; margin: 1em 0;">
-<strong>Note for Windows:</strong> Trac's FCGI does not run under Windows, as Windows does not implement Socket.fromfd, which is used by _fcgi.py
-</p>
-}}}
+'''Note for Windows:''' Trac's FCGI does not run under Windows, as Windows does not implement `Socket.fromfd`, which is used by `_fcgi.py`. If you want to connect to IIS, your choice may be [trac:TracOnWindowsIisAjp AJP].
== Simple Apache configuration ==
@@ -84,12 +79,15 @@
lighttpd is a secure, fast, compliant and very flexible web-server that has been optimized for high-performance
environments. It has a very low memory footprint compared to other web servers and takes care of CPU load.
-For using `trac.fcgi` with lighttpd add the following to your lighttpd.conf:
+For using `trac.fcgi`(prior to 0.11) / fcgi_frontend.py (0.11) with lighttpd add the following to your lighttpd.conf:
{{{
+#var.fcgi_binary="/path/to/fcgi_frontend.py" # 0.11 if installed with easy_setup, it is inside the egg directory
+var.fcgi_binary="/path/to/cgi-bin/trac.fcgi" # 0.10 name of prior fcgi executable
fastcgi.server = ("/trac" =>
+
("trac" =>
("socket" => "/tmp/trac-fastcgi.sock",
- "bin-path" => "/path/to/cgi-bin/trac.fcgi",
+ "bin-path" => fcgi_binary,
"check-local" => "disable",
"bin-environment" =>
("TRAC_ENV" => "/path/to/projenv")
@@ -107,7 +105,7 @@
fastcgi.server = ("/first" =>
("first" =>
("socket" => "/tmp/trac-fastcgi-first.sock",
- "bin-path" => "/path/to/cgi-bin/trac.fcgi",
+ "bin-path" => fcgi_binary,
"check-local" => "disable",
"bin-environment" =>
("TRAC_ENV" => "/path/to/projenv-first")
@@ -116,7 +114,7 @@
"/second" =>
("second" =>
("socket" => "/tmp/trac-fastcgi-second.sock",
- "bin-path" => "/path/to/cgi-bin/trac.fcgi",
+ "bin-path" => fcgi_binary,
"check-local" => "disable",
"bin-environment" =>
("TRAC_ENV" => "/path/to/projenv-second")
@@ -130,10 +128,8 @@
Note that the above will result in different processes in any event, even
if both are running from the same `trac.fcgi` script.
{{{
-#!html
-<p style="background: #fdc; border: 2px solid #d00; font-style: italic; padding: 0 .5em; margin: 1em 0;">
-<strong>Note from c00i90wn:</strong> It's very important the order on which server.modules are loaded, if mod_auth is not loaded <strong>BEFORE</strong> mod_fastcgi, then the server will fail to authenticate the user.
-</p>
+#!div class=important
+'''Note''' It's very important the order on which server.modules are loaded, if mod_auth is not loaded '''BEFORE''' mod_fastcgi, then the server will fail to authenticate the user.
}}}
For authentication you should enable mod_auth in lighttpd.conf 'server.modules', select auth.backend and auth rules:
{{{
@@ -192,7 +188,7 @@
fastcgi.server = ("/trac" =>
("trac" =>
("socket" => "/tmp/trac-fastcgi.sock",
- "bin-path" => "/path/to/cgi-bin/trac.fcgi",
+ "bin-path" => fcgi_binary,
"check-local" => "disable",
"bin-environment" =>
("TRAC_ENV" => "/path/to/projenv")
@@ -211,7 +207,7 @@
("trac" =>
(
"socket" => "/tmp/trac.sock",
- "bin-path" => "/path/to/cgi-bin/trac.fcgi",
+ "bin-path" => fcgi_binary,
"check-local" => "disable",
"bin-environment" =>
("TRAC_ENV_PARENT_DIR" => "/path/to/parent/dir/of/projects/" )
@@ -237,7 +233,7 @@
fastcgi.server = ("/trac" =>
("trac" =>
("socket" => "/tmp/trac-fastcgi.sock",
- "bin-path" => "/path/to/cgi-bin/trac.fcgi",
+ "bin-path" => fcgi_binary,
"check-local" => "disable",
"bin-environment" =>
("TRAC_ENV" => "/path/to/projenv",
@@ -246,7 +242,7 @@
)
)
}}}
-For details about languages specification see TracFaq question 2.13.
+For details about languages specification see [trac:TracFaq TracFaq] question 2.13.
Other important information like [http://trac.lighttpd.net/trac/wiki/TracInstall this updated TracInstall page], [wiki:TracCgi#MappingStaticResources and this] are useful for non-fastcgi specific installation aspects.
@@ -259,11 +255,11 @@
If nothing else helps and trac.fcgi doesn't start with lighttpd settings __server.username = "www-data"__, __server.groupname = "www-data"__, then in the `bin-environment` section set `PYTHON_EGG_CACHE` to the home directory of `www-data` or some other directory accessible to this account for writing.
-== Simple LiteSpeed Configuration ==
+== Simple !LiteSpeed Configuration ==
The FastCGI front-end was developed primarily for use with alternative webservers, such as [http://www.litespeedtech.com/ LiteSpeed].
-LiteSpeed web server is an event-driven asynchronous Apache replacement designed from the ground-up to be secure, scalable, and operate with minimal resources. LiteSpeed can operate directly from an Apache config file and is targeted for business-critical environments.
+!LiteSpeed web server is an event-driven asynchronous Apache replacement designed from the ground-up to be secure, scalable, and operate with minimal resources. !LiteSpeed can operate directly from an Apache config file and is targeted for business-critical environments.
Setup
@@ -320,11 +316,122 @@
link = http://yourdomain.com/trac/ <--- link of graphic logo
}}}
-7) Restart LiteSpeed, “lswsctrl restart”, and access your new Trac project at:
+7) Restart !LiteSpeed, “lswsctrl restart”, and access your new Trac project at:
{{{
http://yourdomain.com/trac/
}}}
+=== Simple Nginx Configuration ===
+
+1) Nginx configuration snippet - confirmed to work on 0.5.36
+{{{
+ server {
+ listen 10.9.8.7:443;
+ server_name trac.example;
+
+ ssl on;
+ ssl_certificate /etc/ssl/trac.example.crt;
+ ssl_certificate_key /etc/ssl/trac.example.key;
+
+ ssl_session_timeout 5m;
+
+ ssl_protocols SSLv2 SSLv3 TLSv1;
+ ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
+ ssl_prefer_server_ciphers on;
+
+ location / {
+ auth_basic "trac realm";
+ auth_basic_user_file /home/trac/htpasswd;
+
+ # full path
+ if ($uri ~ ^/([^/]+)(/.*)) {
+ set $script_name $1;
+ set $path_info $2;
+ }
+
+ # index redirect
+ if ($uri ~ ^/([^/]+)$) {
+ rewrite (.+) $1/ permanent;
+ }
+
+ # socket address
+ fastcgi_pass unix:/home/trac/run/instance.sock;
+
+ # python - wsgi specific
+ fastcgi_param HTTPS on;
+
+ ## WSGI REQUIRED VARIABLES
+ # WSGI application name - trac instance prefix.
+ fastcgi_param SCRIPT_NAME /$script_name;
+ fastcgi_param PATH_INFO $path_info;
+
+ ## WSGI NEEDED VARIABLES - trac warns about them
+ fastcgi_param REQUEST_METHOD $request_method;
+ fastcgi_param SERVER_NAME $server_name;
+ fastcgi_param SERVER_PORT $server_port;
+ fastcgi_param SERVER_PROTOCOL $server_protocol;
+
+ # for authentication to work
+ fastcgi_param REMOTE_USER $remote_user;
+ }
+ }
+}}}
+
+2) Modified trac.fcgi:
+
+{{{
+#!/usr/bin/env python
+import os
+sockaddr = '/home/trac/run/instance.sock'
+os.environ['TRAC_ENV'] = '/home/trac/instance'
+
+try:
+ from trac.web.main import dispatch_request
+ import trac.web._fcgi
+
+ fcgiserv = trac.web._fcgi.WSGIServer(dispatch_request,
+ bindAddress = sockaddr, umask = 7)
+ fcgiserv.run()
+
+except SystemExit:
+ raise
+except Exception, e:
+ print 'Content-Type: text/plain\r\n\r\n',
+ print 'Oops...'
+ print
+ print 'Trac detected an internal error:'
+ print
+ print e
+ print
+ import traceback
+ import StringIO
+ tb = StringIO.StringIO()
+ traceback.print_exc(file=tb)
+ print tb.getvalue()
+
+}}}
+
+3) reload nginx and launch trac.fcgi like that:
+
+{{{
+trac@trac.example ~ $ ./trac-standalone-fcgi.py
+}}}
+
+The above assumes that:
+ * There is a user named 'trac' for running trac instances and keeping trac environments in its home directory.
+ * /home/trac/instance contains a trac environment
+ * /home/trac/htpasswd contains authentication information
+ * /home/trac/run is owned by the same group the nginx runs under
+ * and if your system is Linux the /home/trac/run has setgid bit set (chmod g+s run)
+ * and patch from ticket #T7239 is applied, or you'll have to fix the socket file permissions every time
+
+Unfortunately nginx does not support variable expansion in fastcgi_pass directive.
+Thus it is not possible to serve multiple trac instances from one server block.
+
+If you worry enough about security, run trac instances under separate users.
+
+Another way to run trac as a FCGI external application is offered in ticket #T6224
+
----
-See also TracCgi, TracModPython, TracInstall, TracGuide
\ No newline at end of file
+See also TracCgi, TracModPython, TracInstall, TracGuide, [trac:TracNginxRecipe TracNginxRecipe]
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracFineGrainedPermissions
^
|
@@ -9,7 +9,7 @@
=== !AuthzPolicy ===
An example policy based on an Authz-style system has been added. See
-[source:trunk/sample-plugins/permissions/authz_policy.py] for details. (See also [source:trunk/sample-plugins/permissions] for more samples.)
+[trac:source:branches/0.11-stable/sample-plugins/permissions/authz_policy.py authz_policy.py] for details (current version requires >= Python 2.4). (See also [trac:source:branches/0.11-stable/sample-plugins/permissions sample-plugins/permissions] for more samples.)
- Install [http://www.voidspace.org.uk/python/configobj.html ConfigObj] (required).
- Copy authz_policy.py into your plugins directory.
@@ -60,7 +60,7 @@
=== mod_authz_svn-like permission policy ===
-At the time of this writing, the old fine grained permissions system from Trac 0.10 and before used for restricting access to the repository has not yet been converted to a permission policy component, but from the user point of view, this makes little if no differences.
+At the time of this writing, the old fine grained permissions system from Trac 0.10 and before used for restricting access to the repository has not yet been converted to a permission policy component, but from the user point of view, this makes little if no difference.
That kind of fine-grained permission control needs a definition file, which is the one used by Subversion's mod_authz_svn.
More information about this file format and about its usage in Subversion is available in the [http://svnbook.red-bean.com/svnbook/book.html#svn-ch-6-sect-4.4.2 Subversion Book (Per-Directory Access Control)].
@@ -116,5 +116,10 @@
For information about how to restrict access to entire projects in a multiple project environment see [trac:wiki:TracMultipleProjectsSVNAccess]
+== Getting TracFineGrainedPermissions to work ==
+
+Don't forget to restart Trac engine to apply new configuration if you are running tracd standalone server.
+
----
-See also: TracPermissions
\ No newline at end of file
+See also: TracPermissions
+http://trac-hacks.org/wiki/FineGrainedPageAuthzEditorPlugin for a simple editor plugin.
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracGuide
^
|
@@ -31,10 +31,12 @@
* TracReports -- Writing and using reports.
* TracQuery -- Executing custom ticket queries.
* TracRoadmap -- The roadmap helps tracking project progress.
- * [http://trac.edgewall.org/wiki/TracFaq Trac FAQ] - A collection of Frequently Asked Questions (on the project website).
+ * [trac:TracFaq Trac FAQ] - A collection of Frequently Asked Questions (on the project website).
== Support and Other Sources of Information ==
If you are looking for a good place to ask a question about Trac, look no further than the [http://trac.edgewall.org/wiki/MailingList MailingList]. It provides a friendly environment to discuss openly among Trac users and developers.
See also the TracSupport page for more information resources.
+Finally, developer documentation can be found in [trac:TracDev TracDev] and its sub-pages.
+
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracIni
^
|
@@ -1,10 +1,12 @@
= The Trac Configuration File =
-
[[TracGuideToc]]
+Trac configuration is done by editing the '''`trac.ini`''' config file, located in `<projectenv>/conf/trac.ini`. Changes to the configuration are usually reflected immediately, though changes to the `[components]` or `[logging]` sections will require restarting the web server. You may also need to restart the web server after creating a global configuration file when none was previously present.
+
== Global Configuration ==
In versions prior to 0.11, the global configuration was by default located in `$prefix/share/trac/conf/trac.ini` or sometimes /etc/trac/trac.ini depending on the distribution. If you're upgrading, you may want to specify that file to inherit from.
+Literally, when you're upgrading to 0.11, you have to add an `inherit`-section to your project's `trac.ini` file. Additionally you have to move your customized templates and common images from `$prefix/share/trac/...` to the new location.
Global options will be merged with the environment-specific options, where local options override global options. The options file is specified as follows:
{{{
@@ -64,12 +66,17 @@
in all cases. This section enables one to easily create ''groups'' of states
that will be shown in different colors in the milestone progress bar.
-Example configuration (which is also the default):
+Example configuration (the default only has closed and active):
{{{
closed = closed
closed.order = 0 # sequence number in the progress bar
closed.query_args = group=resolution # optional extra param for the query
-closed.overall_completion = true # count for overall completion
+closed.overall_completion = true # indicates groups that count for overall completion percentage
+
+new = new
+new.order = 1
+new.css_class = new
+new.label = new
active = * # one catch-all group is allowed
active.order = 1
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracInstall
^
|
@@ -8,10 +8,11 @@
== Short - Install a released version ==
For the quick install, make sure you have [http://python.org Python-2.5], [http://peak.telecommunity.com/DevCenter/EasyInstall#installing-easy-install easy_install] and SQlite-3.3.4 installed (or above).
{{{
-sudo easy_install Trac==0.11
+sudo easy_install Trac
}}}
-== Requirements - also older versions possible ==
+== Requirements ==
+The hardware requirements for running Trac obviously depend on the expected data volume (number of wiki pages, tickets, revisions) and traffic. Very small projects will run fine with a 500MHz processor and 128MB RAM using SQLite. In general, the more RAM, the better. A fast hard disk also helps.
To install Trac, the following software packages must be installed:
@@ -20,50 +21,52 @@
* For RPM-based systems you might also need the `python-devel` and `python-xml` packages.
* See instructions in ["TracOnWindows/Python2.5"]
* [http://peak.telecommunity.com/DevCenter/setuptools setuptools], version >= 0.6
- * [http://genshi.edgewall.org/wiki/Download Genshi], version >= 0.4.1
+ * [http://genshi.edgewall.org/wiki/Download Genshi], version >= 0.5 (was version >= 0.4.1 on previous 0.11 release candidates)
* You also need a database system and the corresponding python drivers for it.
The database can be either SQLite, PostgreSQL or ''MySQL (experimental)''.
- * optional if some plugins require it: [http://www.clearsilver.net/ ClearSilver]
+ * Optional if some plugins require it: [http://www.clearsilver.net/ ClearSilver]
-=== For SQLite ===
+==== For SQLite ====
- * [http://www.sqlite.org/ SQLite], version 3.3.4 and above preferred.
- * If not using Python-2.5: [http://pysqlite.org/ PySQLite], version 1.x (for SQLite 2.x) or version 2.x (for SQLite 3.x), version 2.3.2 preferred. For details see PySqlite
+ * [http://www.sqlite.org/ SQLite], version 3.3.4 and above preferred (note: it is preinstalled in Python 2.5.2).
+ * If not using Python-2.5: [http://pysqlite.org/ PySQLite], version 1.x (for SQLite 2.x) or version 2.x (for SQLite 3.x), version 2.3.2 preferred. For details see [trac:PySqlite PySqlite]
''Note: It appears that PySQLite 2.x is required for Trac 0.9+/SQLite 3.x if you plan to use the 'trac-post-commit-hook.py' script available from the 'contrib' section of the source repository.''
''Note: Users of Mac OS X please take care; the Apple-supplied SQLite contains additional code to support file locking on network filesystems like AFP or SMB. This is not presently (3.3.6) in the mainline sources, so if you build your own SQLite from source it will not function correctly on such filesystems - typically it gives the error "{{{database is locked}}}". [http://www.alastairs-place.net/2006/07/sqlite_and_mac/ A patch] is available for version 3.3.6, based on Apple's code, otherwise you're probably best off using the Apple supplied version (presently 3.1.3).''
-=== For PostgreSQL ===
+==== For PostgreSQL ====
* [http://www.postgresql.org/ PostgreSQL]
- * [http://initd.org/projects/psycopg2 psycopg2] or [http://pypgsql.sourceforge.net/ pyPgSQL]
+ * [http://initd.org/projects/psycopg2 psycopg2]
+ * See [trac:wiki:DatabaseBackend#Postgresql DatabaseBackend]
'''Warning''': PostgreSQL 8.3 uses a strict type checking mechanism. To use Trac with the 8.3 Version of PostgreSQL, you will need [http://trac.edgewall.org/changeset/6512 trac-0.11] or later.
-=== For MySQL ===
+==== For MySQL ====
-'''Warning''': MySQL support is currently ''still'' experimental. That means it works for some people, but several issues remain, in particular regarding the use of unicode and the key length in the repository cache. See MySqlDb for more detailed information.
+'''Warning''': MySQL support is currently ''still'' experimental. That means it works for some people, but several issues remain, in particular regarding the use of unicode and the key length in the repository cache. See [trac:MySqlDb MySqlDb] for more detailed information.
* [http://mysql.com/ MySQL], version 4.1 or later
* [http://sf.net/projects/mysql-python MySQLdb], version 1.2.1 or later
-=== Optional Requirements ===
+== Optional Requirements ==
==== Version Control System ====
'''Please note:''' if using Subversion, Trac must be installed on the '''same machine'''. Remote repositories are currently not supported.
- * [http://subversion.tigris.org/ Subversion], version >= 1.0. (versions recommended: 1.2.4, 1.3.2 or 1.4.2) and the '''''corresponding''''' Python bindings. For troubleshooting, check TracSubversion
+ * [http://subversion.tigris.org/ Subversion], version >= 1.0. (versions recommended: 1.2.4, 1.3.2 or 1.4.2) and the '''''corresponding''''' Python bindings. For troubleshooting, check [trac:TracSubversion TracSubversion]
* Trac uses the [http://svnbook.red-bean.com/svnbook-1.1/ch08s02.html#svn-ch-8-sect-2.3 SWIG] bindings included in the Subversion distribution, '''not''' [http://pysvn.tigris.org/ PySVN] (which is sometimes confused with the standard SWIG bindings).
* If Subversion was already installed without the SWIG bindings, on Unix you'll need to re-`configure` Subversion and `make swig-py`, `make install-swig-py`.
* There are [http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91 pre-compiled bindings] available for win32.
- * Support for other version control systems is provided via third-parties. See PluginList and VersioningSystemBackend.
+ * Support for other version control systems is provided via third-parties. See [trac:PluginList PluginList] and [trac:VersioningSystemBackend VersioningSystemBackend].
==== Web Server ====
* A CGI-capable web server (see TracCgi), or
* a [http://www.fastcgi.com/ FastCGI]-capable web server (see TracFastCgi), or
- * [http://httpd.apache.org/ Apache] with [http://code.google.com/p/modwsgi/ mod_wsgi] (see [wiki:TracModWSGI])
+ * an [http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html AJP]-capable web server (see [trac:TracOnWindowsIisAjp TracOnWindowsIisAjp]), or
+ * [http://httpd.apache.org/ Apache] with [http://code.google.com/p/modwsgi/ mod_wsgi] (see [wiki:TracModWSGI] or http://code.google.com/p/modwsgi/wiki/IntegrationWithTrac)
* This should work with Apache 1.3, 2.0 or 2.2 and promises to deliver more performance than using mod_python. A little less mature than mod_python.
* [http://httpd.apache.org/ Apache] with [http://www.modpython.org/ mod_python 3.1.3+] (see TracModPython)
* When installing mod_python the development versions of Python and Apache are required (actually the libraries and header files)
@@ -72,21 +75,20 @@
==== Other Python Utilities ====
* [http://docutils.sourceforge.net/ docutils], version >= 0.3.9 for WikiRestructuredText.
- * [http://pygments.pocoo.org Pygments] for [wiki:TracSyntaxColoring syntax highlighting], also [http://silvercity.sourceforge.net/ SilverCity] and/or [http://gnu.org/software/enscript/enscript.html Enscript] may still be used.
- * Note that !SilverCity 0.9.6 has a [http://sourceforge.net/tracker/index.php?func=detail&aid=1424436&group_id=45693&atid=443739 bug] that breaks Python syntax highlighting in Trac. Until an update is made available, we recommend using version 0.9.5.
+ * [http://pygments.pocoo.org Pygments] for '''syntax highlighting''', although [http://silvercity.sourceforge.net/ SilverCity] >= 0.9.7 and/or [http://gnu.org/software/enscript/enscript.html GNU Enscript] are also possible. Refer to TracSyntaxColoring for details.
* [http://pytz.sf.net pytz] to get a complete list of time zones, otherwise Trac will fall back on a shorter list from an internal time zone implementation.
-'''Attention''': The various available versions of these dependencies are not necessarily interchangable, so please pay attention to the version numbers above. If you are having trouble getting Trac to work please double-check all the dependencies before asking for help on the MailingList or IrcChannel.
+'''Attention''': The various available versions of these dependencies are not necessarily interchangable, so please pay attention to the version numbers above. If you are having trouble getting Trac to work please double-check all the dependencies before asking for help on the [trac:MailingList MailingList] or [trac:IrcChannel IrcChannel].
-Please refer to the documentation of these packages to find out how they are best installed. In addition, most of the [wiki:TracInstallPlatforms platform-specific instructions] also describe the installation of the dependencies. Keep in mind however that the information there ''probably concern older versions of Trac than the one you're installing'' (there are even some pages that are still talking about Trac 0.8!).
+Please refer to the documentation of these packages to find out how they are best installed. In addition, most of the [trac:TracInstallPlatforms platform-specific instructions] also describe the installation of the dependencies. Keep in mind however that the information there ''probably concern older versions of Trac than the one you're installing'' (there are even some pages that are still talking about Trac 0.8!).
== Installing Trac ==
One way to install Trac is using `setuptools`.
With setuptools you can install Trac from the subversion repository; for example,
-to install release version 0.11b2 do:
+to install release version 0.11 do:
{{{
-easy_install http://svn.edgewall.org/repos/trac/tags/trac-0.11b2
+easy_install http://svn.edgewall.org/repos/trac/tags/trac-0.11
}}}
But of course the python-typical setup at the top of the source directory also works:
@@ -101,7 +103,7 @@
The script will also install the [wiki:TracAdmin trac-admin] command-line tool, used to create and maintain [wiki:TracEnvironment project environments], as well as the [wiki:TracStandalone tracd] standalone server.
-=== Advanced Options ===
+==== Advanced Options ====
To install Trac to a custom location, or find out about other advanced installation options, run:
{{{
@@ -138,6 +140,7 @@
chown -R apache.apache /path/to/myproject
+'''Warning: If the trac.cgi files are not installed where you expect, then the current documentation is insufficient; it might be necessary to use the 'deploy' command in trac-admin. See tickets http://trac.edgewall.org/ticket/7312 and possibly http://trac.edgewall.org/ticket/6827'''
== Running the Standalone Server ==
@@ -156,7 +159,13 @@
Trac provides three options for connecting to a "real" web server: [wiki:TracCgi CGI], [wiki:TracFastCgi FastCGI] and [wiki:TracModPython mod_python]. For decent performance, it is recommended that you use either FastCGI or mod_python.
-If you're not afraid of running development code, you can also try running Trac on [wiki:TracModWSGI mod_wsgi]. This should deliver even better performance than mod_python, but the module is not considered stable just yet.
+If you're not afraid of running newer code, you can also try running Trac on [wiki:TracModWSGI mod_wsgi]. This should deliver even better performance than mod_python, but the module isn't as extensively tested as mod_python.
+
+Trac also supports [trac:TracOnWindowsIisAjp AJP] which may be your choice if you want to connect to IIS.
+
+==== Setting up the Plugin Cache ====
+
+Some Python plugins need to be extracted to a cache directory. By default the cache resides in the home directory of the current user. When running Trac on a Web Server as a dedicated user (which is highly recommended) who has no home directory, this might prevent the plugins from starting. To override the cache location you can set the PYTHON_EGG_CACHE environment variable. Refer to your server documentation for detailed instructions.
== Configuring Authentication ==
@@ -168,7 +177,7 @@
== Trac 0.11 & SVN on Mac OS X Leopard (10.5) ==
- * TracOnLeopardServer
+ * [trac:TracOnLeopardServer TracOnLeopardServer]
== Using Trac ==
@@ -178,7 +187,7 @@
'' Enjoy! ''
-[wiki:TracTeam The Trac Team]
+[trac:TracTeam The Trac Team]
----
See also: TracGuide, TracCgi, TracFastCgi, TracModPython, [wiki:TracModWSGI], TracUpgrade, TracPermissions
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracInterfaceCustomization
^
|
@@ -54,7 +54,7 @@
See also TracNavigation for a more detailed explanation of the mainnav and metanav terms.
-== Site Appearance ==
+== Site Appearance == #SiteAppearance
Trac is using [http://genshi.edgewall.org Genshi] as the templating engine. Documentation is yet to be written, in the meantime the following tip should work.
@@ -117,7 +117,8 @@
Also note that the `site.html` (despite its name) can be put in a common templates directory - see the `[inherit] templates_dir` option. This could provide easier maintainence (and a migration path from 0.10 for larger installations) as one new global `site.html` file can be made to include any existing header, footer and newticket snippets.
-== Project List ==
+== Project List == #ProjectList
+
You can use a custom Genshi template to display the list of projects if you are using Trac with multiple projects.
The following is the basic template used by Trac to display a list of links to the projects. For projects that could not be loaded it displays an error message. You can use this as a starting point for your own index template.
@@ -158,6 +159,7 @@
For [wiki:TracModPython mod_python]:
{{{
+PythonOption TracEnvParentDir /parent/dir/of/projects
PythonOption TracEnvIndexTemplate /path/to/template
}}}
@@ -178,5 +180,17 @@
$ set TRAC_ENV_INDEX_TEMPLATE=/path/to/template
}}}
+== Project Templates ==
+
+The appearance of each individual Trac environment (that is, instance of a project) can be customized independently of other projects, even those hosted by the same server. The recommended way is to use a `site.html` template (see [#SiteAppearance]) whenever possible. Using `site.html` means changes are made to the original templates as they are rendered, and you should not normally need to redo modifications whenever Trac is upgraded. If you do make a copy of `theme.html` or any other Trac template, you need to migrate your modifiations to the newer version - if not, new Trac features or bug fixes may not work as expected.
+
+With that word of caution, any Trac template may be copied and customized. The default Trac templates are located inside the installed Trac egg (`/usr/lib/pythonVERSION/site-packages/Trac-VERSION.egg/trac/templates, .../trac/ticket/templates, .../trac/wiki/templates, ++`). The [#ProjectList] template file is called `index.html`, while the template responsible for main layout is called `theme.html`. Page assets such as images and CSS style sheets are located in the egg's `trac/htdocs` directory.
+
+However, do not edit templates or site resources inside the Trac egg - installing Trac again can completely delete your modifications. Instead use one of two alternatives:
+ * For a modification to one project only, copy the template to project `templates` directory.
+ * For a modification shared by several projects, copy the template to a shared location and have each project point to this location using the `[inherit] templates_dir =` trac.ini option.
+
+Trac resolves requests for a template by first looking inside the project, then in any inherited templates location, and finally inside the Trac egg.
+
----
See also TracGuide, TracIni
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracLinks
^
|
@@ -18,29 +18,31 @@
Some examples:
* Tickets: '''!#1''' or '''!ticket:1'''
- * Ticket comments: '''!comment:ticket:1:2'''
+ * Ticket comments: '''!comment:1:ticket:2'''
* Reports: '''!{1}''' or '''!report:1'''
- * Changesets: '''!r1''', '''![1]''', '''!changeset:1''' or (restricted) '''![1/trunk]''', '''!changeset:1/trunk''', '''![2:5/trunk]'''
- * Revision log: '''!r1:3''', '''![1:3]''' or '''!log:@1:3''', '''!log:trunk@1:3'''
- * Diffs (requires [milestone:0.10 0.10]): '''!diff:@1:3''', '''!diff:tags/trac-0.9.2/wiki-default//tags/trac-0.9.3/wiki-default''' or '''!diff:trunk/trac@3538//sandbox/vc-refactoring@3539'''
+ * Changesets: '''!r1''', '''![1]''', '''!changeset:1''' or (restricted) '''![1/trunk]''', '''!changeset:1/trunk'''
+ * Revision log: '''!r1:3''', '''![1:3]''' or '''!log:@1:3''', '''!log:trunk@1:3''', '''![2:5/trunk]'''
+ * Diffs (requires [trac:milestone:0.10 0.10]): '''!diff:@1:3''', '''!diff:tags/trac-0.9.2/wiki-default//tags/trac-0.9.3/wiki-default''' or '''!diff:trunk/trac@3538//sandbox/vc-refactoring@3539'''
* Wiki pages: '''!CamelCase''' or '''!wiki:CamelCase'''
* Parent page: '''![..]'''
* Milestones: '''!milestone:1.0'''
- * Attachment: '''!attachment:ticket:944:attachment.1073.diff'''
+ * Attachment: '''!attachment:example.tgz''' (for current page attachment), '''!attachment:attachment.1073.diff:ticket:944'''
+(absolute path)
* Files: '''!source:trunk/COPYING'''
* A specific file revision: '''!source:/trunk/COPYING@200'''
* A particular line of a specific file revision: '''!source:/trunk/COPYING@200#L25'''
Display:
* Tickets: #1 or ticket:1
- * Ticket comments: comment:ticket:1:2
+ * Ticket comments: comment:1:ticket:2
* Reports: {1} or report:1
- * Changesets: r1, [1], changeset:1, or (restricted) [1/trunk], changeset:1/trunk, [2:5/trunk]
- * Revision log: r1:3, [1:3] or log:@1:3, log:trunk@1:3
- * Diffs (requires [milestone:0.10 0.10]): diff:@20:30, diff:tags/trac-0.9.2/wiki-default//tags/trac-0.9.3/wiki-default or diff:trunk/trac@3538//sandbox/vc-refactoring/trac@3539
+ * Changesets: r1, [1], changeset:1 or (restricted) [1/trunk], changeset:1/trunk
+ * Revision log: r1:3, [1:3] or log:@1:3, log:trunk@1:3, [2:5/trunk]
+ * Diffs (requires [milestone:0.10 0.10]): diff:@1:3, diff:tags/trac-0.9.2/wiki-default//tags/trac-0.9.3/wiki-default or diff:trunk/trac@3538//sandbox/vc-refactoring@3539
* Wiki pages: CamelCase or wiki:CamelCase
- * Parent page: '''[..]'''
+ * Parent page: [..]
* Milestones: milestone:1.0
- * Attachment: attachment:ticket:944:attachment.1073.diff
+ * Attachment: attachment:example.tgz (for current page attachment), attachment:attachment.1073.diff:ticket:944
+(absolute path)
* Files: source:trunk/COPYING
* A specific file revision: source:/trunk/COPYING@200
* A particular line of a specific file revision: source:/trunk/COPYING@200#L25
@@ -91,17 +93,17 @@
Hint: when you move your mouse over the title of a section, a '¶' character will be displayed. This is a link to that specific section and you can use this to copy the `#...` part inside a relative link to an anchor.
-To create a link to a SubWiki-page just use a '/':
+To create a link to a [trac:SubWiki SubWiki]-page just use a '/':
{{{
WikiPage/SubWikiPage or ./SubWikiPage
}}}
-To link from a SubWiki page to a parent, simply use a '..':
+To link from a [trac:SubWiki SubWiki] page to a parent, simply use a '..':
{{{
[..]
}}}
-To link from a SubWiki page to a sibling page, use a '../':
+To link from a [trac:SubWiki SubWiki] page to a sibling page, use a '../':
{{{
[../Sibling see next sibling]
}}}
@@ -152,7 +154,7 @@
* !wiki:"The whitespace convention"
* !attachment:'the file.txt' or
* !attachment:"the file.txt"
- * !attachment:"ticket:123:the file.txt"
+ * !attachment:"the file.txt:ticket:123"
=== Escaping Links ===
@@ -184,8 +186,23 @@
The link syntax for attachments is as follows:
* !attachment:the_file.txt creates a link to the attachment the_file.txt of the current object
- * !attachment:wiki:MyPage:the_file.txt creates a link to the attachment the_file.txt of the !MyPage wiki page
- * !attachment:ticket:753:the_file.txt creates a link to the attachment the_file.txt of the ticket 753
+ * !attachment:the_file.txt:wiki:MyPage creates a link to the attachment the_file.txt of the !MyPage wiki page
+ * !attachment:the_file.txt:ticket:753 creates a link to the attachment the_file.txt of the ticket 753
+
+Note that the older way, putting the filename at the end, is still supported: !attachment:ticket:753:the_file.txt.
+
+If you'd like to create a direct link to the content of the attached file instead of a link to the attachment page, simply use `raw-attachment:` instead of `attachment:`.
+
+This can be useful for pointing directly to an HTML document, for example. Note that for this use case, you'd have to allow the web browser to render the content by setting `[attachment] render_unsafe_content = yes` (see TracIni#attachment-section). Caveat: only do that in environments for which you're 100% confident you can trust the people who are able to attach files, as otherwise this would open up your site to [wikipedia:Cross-site_scripting cross-site scripting] attacks.
+
+See also [#export:links].
+
+=== comment: links ===
+
+When you're inside a given tickets, you can simply write e.g. !comment:3 to link to the third change comment.
+It's also possible to link to a comment of a specific ticket from anywhere using one of the following syntax:
+ - !comment:3:ticket:123
+ - !ticket:123#comment:3 (note that you can't write !#123#!comment:3!)
=== query: links ===
@@ -245,9 +262,9 @@
* `export:123:/some/file` - get revision 123 of the specified file
* `export:/some/file@123` - get revision 123 of the specified file
-This can be very useful for displaying HTML documentation with correct stylesheets and images, in case that has been checked in the repository.
+This can be very useful for displaying XML or HTML documentation with correct stylesheets and images, in case that has been checked in into the repository. Note that for this use case, you'd have to allow the web browser to render the content by setting `[browser] render_unsafe_content = yes` (see TracIni#browser-section), otherwise Trac will force the files to be downloaded as attachments for security concerns.
-If the path is to a directory in the repository instead of a specific file, the source browser will be used to display the directory (identical to the result of `source:/some/dir`.
+If the path is to a directory in the repository instead of a specific file, the source browser will be used to display the directory (identical to the result of `source:/some/dir`).
==== log: links ====
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracModPython
^
|
@@ -12,7 +12,8 @@
LoadModule python_module modules/mod_python.so
}}}
- ''Note: The exact path to the module depends on how the HTTPD installation is laid out.''
+''Note: The exact path to the module depends on how the HTTPD installation is laid out.''
+
On Debian using apt-get
{{{
apt-get install libapache2-mod-python libapache2-mod-python-doc
@@ -56,15 +57,20 @@
# For multiple projects
PythonOption TracEnvParentDir /var/trac/myprojects
# For the index of multiple projects
- PythonOption TracEnvIndexTemplate /srv/www/htdocs/trac/project_list_tepmlate.html
+ PythonOption TracEnvIndexTemplate /srv/www/htdocs/trac/project_list_template.html
# A space delimitted list, with a "," between key and value pairs.
PythonOption TracTemplateVars key1,val1 key2,val2
# Useful to get the date in the wanted order
PythonOption TracLocale en_GB.UTF8
# See description above
PythonOption TracUriRoot /projects/myproject
- # Override default python egg cache location
- PythonOption PYTHON_EGG_CACHE /var/trac/myprojects/egg-cache
+}}}
+
+=== Python Egg Cache ===
+
+Compressed python eggs like Genshi are normally extracted into a directory named `.python-eggs` in the users home directory. Since apache's home usually is not writable an alternate egg cache directory can be specified like this:
+{{{
+PythonOption PYTHON_EGG_CACHE /var/trac/myprojects/egg-cache
}}}
=== Configuring Authentication ===
@@ -218,11 +224,13 @@
</VirtualHost>
}}}
-if you have issues with login try using `<LocationMatch>` instead of `<Location>`
+This does not seem to work in all cases. What you can do if it does not:
+ * Try using `<LocationMatch>` instead of `<Location>`
+ * <Location /> may, in your server setup, refer to the complete host instead of simple the root of the server. This means that everything (including the login directory referenced below) will be sent to python and authentication does not work (i.e. you get the infamous Authentication information missing error). If this applies to you, try using a sub-directory for trac instead of the root (i.e. /web/ and /web/login instead of / and /login).
For a virtual host that supports multiple projects replace "`TracEnv`" /var/trac/myproject with "`TracEnvParentDir`" /var/trac/
-Note: !DocumentRoot should not point to your Trac project env. As Asmodai wrote on #trac: "suppose there's a webserer bug that allows disclosure of !DocumentRoot they could then leech the entire Trac environment".
+Note: !DocumentRoot should not point to your Trac project env. As Asmodai wrote on #trac: "suppose there's a webserver bug that allows disclosure of !DocumentRoot they could then leech the entire Trac environment".
== Troubleshooting ==
@@ -263,6 +271,22 @@
It may be possible to work around this with mod_rewrite, but I failed to get this working. In all, it is more hassle than it is worth. Stick to the provided instructions. :)
+A success story: For me it worked out-of-box, with following trivial config:
+{{{
+SetHandler mod_python
+PythonInterpreter main_interpreter
+PythonHandler trac.web.modpython_frontend
+PythonOption TracEnv /system/path/to/this/directory
+PythonOption TracUriRoot /path/on/apache
+
+AuthType Basic
+AuthName "ProjectName"
+AuthUserFile /path/to/.htpasswd
+Require valid-user
+}}}
+
+The TracUriRoot is obviously the path you need to enter to the browser to get to the trac (e.g. domain.tld/projects/trac)
+
=== Win32 Issues ===
If you run trac with mod_python < 3.2 on Windows, uploading attachments will '''not''' work. This problem is resolved in mod_python 3.1.4 or later, so please upgrade mod_python to fix this.
|
[-]
[+]
|
Added |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracModWSGI
^
|
@@ -0,0 +1,71 @@
+= Trac and mod_wsgi =
+
+'''Important note:''' ''Please use either version 1.3 or 2.3 or later of `mod_wsgi`. Version 2.0 has problems with downloading attachments (see [trac:ticket:7205 #7205]).''
+
+[http://code.google.com/p/modwsgi/ mod_wsgi] is an Apache module for running WSGI-compatible Python applications directly on top of Apache:
+
+ The mod_wsgi adapter is an Apache module that provides a WSGI compliant interface for hosting Python based web applications within Apache. The adapter is written completely in C code against the Apache C runtime and for hosting WSGI applications within Apache provides significantly better performance than using existing WSGI adapters for mod_python or CGI.
+
+It is already possible to run Trac on top of mod_wsgi. This can be done by writing the following application script, which is just a Python file, though usually saved with a .wsgi extension).
+
+{{{
+import os
+
+os.environ['TRAC_ENV'] = '/usr/local/trac/mysite'
+os.environ['PYTHON_EGG_CACHE'] = '/usr/local/trac/mysite/eggs'
+
+import trac.web.main
+application = trac.web.main.dispatch_request
+}}}
+
+The {{{TRAC_ENV}}} variable should naturally be the directory for your Trac environment (if you have several Trac environments in a directory, you can also use {{{TRAC_ENV_PARENT_DIR}}} instead), while the {{{PYTHON_EGG_CACHE}}} should be a directory where Python can temporarily extract Python eggs. [[BR]]
+For clarity, you should give this file a {{{.wsgi}}} extension. You should probably put the file in it's own directory, since you will open up its directory to Apache.
+You can create a .wsgi files which handles all this for you by running the TracAdmin command {{{deploy}}}.
+
+If you have installed trac and eggs in a path different from the standard one you should add that path by adding the following code on top of the wsgi script:
+{{{
+import site
+site.addsitedir('/usr/local/trac/lib/python2.4/site-packages')
+}}}
+Change it according to the path you installed the trac libs at.
+
+After you've done preparing your wsgi-script, add the following to your httpd.conf.
+
+{{{
+WSGIScriptAlias /trac /usr/local/trac/mysite/apache/mysite.wsgi
+
+<Directory /usr/local/trac/mysite/apache>
+ WSGIApplicationGroup %{GLOBAL}
+ Order deny,allow
+ Allow from all
+</Directory>
+}}}
+
+Here, the script is in a subdirectory of the Trac environment. In order to let Apache run the script, access to the directory in which the script resides is opened up to all of Apache. Additionally, the {{{WSGIApplicationGroup}}} directive ensures that Trac is always run in the first Python interpreter created by mod_wsgi; this is necessary because the Subversion Python bindings, which are used by Trac, don't always work in other subinterpreters and may cause requests to hang or cause Apache to crash as a result. After adding this configuration, restart Apache, and then it should work.
+
+To test the setup of Apache, mod_wsgi and Python itself (ie. without involving Trac and dependencies), this simple wsgi application can be used to make sure that requests gets served (use as only content in your .wsgi script):
+
+{{{
+def application(environ, start_response):
+ start_response('200 OK',[('Content-type','text/html')])
+ return ['<html><body>Hello World!</body></html>']
+}}}
+
+See also the mod_wsgi [http://code.google.com/p/modwsgi/wiki/IntegrationWithTrac installation instructions] for Trac.
+
+For troubleshooting tips, see the [TracModPython#Troubleshooting mod_python troubleshooting] section, as most Apache-related issues are quite similar, plus discussion of potential [http://code.google.com/p/modwsgi/wiki/ApplicationIssues application issues] when using mod_wsgi.
+
+== Trac with PostgreSQL ==
+
+When using the mod_wsgi adapter with multiple Trac instances and PostgreSQL (or MySQL?) as a database back-end the server can get a lot of open database connections. (and thus PostgreSQL processes)
+
+A workable solution is to disabled connection pooling in Trac. This is done by setting poolable = False in trac.db.postgres_backend on the PostgreSQLConnection class.
+
+But it's not necessary to edit the source of trac, the following lines in trac.wsgi will also work:
+
+{{{
+import trac.db.postgres_backend
+trac.db.postgres_backend.PostgreSQLConnection.poolable = False
+}}}
+
+Now Trac drops the connection after serving a page and the connection count on the database will be kept minimal.
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracNotification
^
|
@@ -106,6 +106,15 @@
to delete these notifications.
+In Thunderbird, there is no such solution if you use IMAP
+(see http://kb.mozillazine.org/Filters_(Thunderbird)#Filtering_the_message_body).
+
+The best you can do is to set "always_notify_updater" in conf/trac.ini to false.
+You will however still get an email if you comment a ticket that you own or have reported.
+
+You can also add this plugin:
+http://trac-hacks.org/wiki/NeverNotifyUpdaterPlugin
+
== Troubleshooting ==
If you cannot get the notification working, first make sure the log is activated and have a look at the log to find if an error message has been logged. See TracLogging for help about the log feature.
@@ -133,7 +142,7 @@
sudo -u www-data telnet localhost 25
}}}
-In such a case, you need to configure your server so that the web server is authorize to post to the SMTP server. The actual settings depend on your Linux distribution and current security policy. You may find help browsing the Trac MailingList archive.
+In such a case, you need to configure your server so that the web server is authorized to post to the SMTP server. The actual settings depend on your Linux distribution and current security policy. You may find help browsing the Trac [trac:MailingList MailingList] archive.
Relevant ML threads:
* SELinux: http://article.gmane.org/gmane.comp.version-control.subversion.trac.general/7518
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracPermissions
^
|
@@ -3,13 +3,24 @@
Trac uses a simple, case sensitive, permission system to control what users can and can't access.
-Permission privileges are managed using the [TracAdmin trac-admin] tool or the ''General / Permissions'' panel in the ''Admin'' web interface.
+Permission privileges are managed using the [TracAdmin trac-admin] tool or (new in version 0.11) the ''General / Permissions'' panel in the ''Admin'' tab of the web interface.
In addition to the default permission policy described in this page, it is possible to activate additional permission policies by enabling plugins and listing them in the `[trac] permission_policies` configuration entry in the TracIni. See TracFineGrainedPermissions for more details.
Non-authenticated users accessing the system are assigned the name "anonymous". Assign permissions to the "anonymous" user to set privileges for anonymous/guest users. The parts of Trac that a user does not have the privileges for will not be displayed in the navigation.
In addition to these privileges, users can be granted additional individual rights in effect when authenticated and logged into the system. All logged in users belong to the virtual group "authenticated", which inherits permissions from "anonymous".
+== Graphical Admin Tab ==
+''This feature is new in version 0.11.''
+
+To access this tab, a user must have `TRAC_ADMIN privileges`. This can be performed as follows (more on the trac-admin script below):
+{{{
+ $ trac-admin /path/to/projenv permission add bob TRAC_ADMIN
+}}}
+
+Then, the user will be able to see the Admin tab, and can then access the permissions menu. This menu will allow you to perform all the following actions, but from the browser without requiring root access to the server (just the correct permissions for your user account).
+
+
== Available Privileges ==
To enable all privileges for a user, use the `TRAC_ADMIN` permission. Having `TRAC_ADMIN` is like being `root` on a *NIX system: it will allow you to perform any operation.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracPlugins
^
|
@@ -1,7 +1,7 @@
= Trac Plugins =
[[TracGuideToc]]
-Since version 0.9, Trac supports [PluginList plugins] that extend the built-in functionality. The plugin functionality is based on the [trac:TracDev/ComponentArchitecture component architecture].
+Since version 0.9, Trac supports [trac:PluginList plugins] that extend the built-in functionality. The plugin functionality is based on the [trac:TracDev/ComponentArchitecture component architecture].
== Requirements ==
@@ -70,7 +70,7 @@
}}}
==== Enabling the plugin ====
-Unlike plugins installed per-environment, you'll have to explicitly enable globally installed plugins via [wiki:TracIni trac.ini]. This is done in the `[components]` section of the configuration file, for example:
+Unlike plugins installed per-environment, you'll have to explicitly enable globally installed plugins via [wiki:TracIni trac.ini]. This also applies to plugins installed in the path specified in the `[inherit] plugins_dir` configuration option. This is done in the `[components]` section of the configuration file, for example:
{{{
[components]
tracspamfilter.* = enabled
@@ -119,15 +119,19 @@
<Location /trac>
SetHandler mod_python
...
- SetEnv PYTHON_EGG_CACHE /path/to/dir
+ PythonOption PYTHON_EGG_CACHE /path/to/dir
</Location>
}}}
- ''Note: this requires the `mod_env` module''
+ ''Note: !SetEnv requires the `mod_env` module which needs to be activated for Apache. In this case the !SetEnv directive can also be used in the `mod_python` Location block.''
For [wiki:TracFastCgi FastCGI], you'll need to `-initial-env` option, or whatever is provided by your web server for setting environment variables.
- ''Note: that if you already use -initial-env to set the project directory for either a single project or parent you will need to add atleast one environment variable inside trac.fcgi as expressed in the example on [wiki:TracFastCgi TracFastCgi].
+ ''Note: that if you already use -initial-env to set the project directory for either a single project or parent you will need to add an additional -initial-env directive to the !FastCgiConfig directive. I.e.
+
+{{{
+FastCgiConfig -initial-env TRAC_ENV=/var/lib/trac -initial-env PYTHON_EGG_CACHE=/var/lib/trac/plugin-cache
+}}}
=== About hook scripts ===
@@ -152,6 +156,7 @@
=== Is the plugin enabled? ===
+
If you install a plugin globally (i.e. ''not'' inside the `plugins` directory of the Trac project environment) you will have to explicitly enable it in [TracIni trac.ini]. Make sure that:
* you actually added the necessary line(s) to the `[components]` section
* the package/module names are correct
@@ -167,7 +172,7 @@
=== Verify you have proper permissions ===
-Some plugins require you have special permissions in order to use them. WebAdmin, for example, requires the user to have TRAC_ADMIN permissions for it to show up on the navigation bar.
+Some plugins require you have special permissions in order to use them. [trac:WebAdmin WebAdmin], for example, requires the user to have TRAC_ADMIN permissions for it to show up on the navigation bar.
=== Is the wrong version of the plugin loading? ===
@@ -179,7 +184,7 @@
=== If all of the above failed ===
-OK, so the logs don't mention plugins, the egg is readable, the python version is correct ''and'' the egg has been installed globally (and is enabled in the trac.ini) and it still doesn't work or give any error messages or any other indication as to why? Hop on the IrcChannel and ask away.
+OK, so the logs don't mention plugins, the egg is readable, the python version is correct ''and'' the egg has been installed globally (and is enabled in the trac.ini) and it still doesn't work or give any error messages or any other indication as to why? Hop on the [trac:IrcChannel IrcChannel] and ask away.
----
See also TracGuide, [trac:PluginList plugin list], [trac:TracDev/ComponentArchitecture component architecture]
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracQuery
^
|
@@ -15,7 +15,7 @@
== Navigating Tickets ==
Clicking on one of the query results will take you to that ticket. You can navigate through the results by clicking the ''Next Ticket'' or ''Previous Ticket'' links just below the main menu bar, or click the ''Back to Query'' link to return to the query page.
-You can safely edit any of the tickets and continue to navigate through the results using the ''Next/Previous/Back to Query'' links after saving your results. When you return to the query ''any tickets which was edited'' will be displayed with italicized text. If one of the tickets was edited such that [[html(<span style="color: grey">it no longer matches the query criteria </span>)]] the text will also be greyed. Lastly, if '''a new ticket matching the query criteria has been created''', it will be shown in bold.
+You can safely edit any of the tickets and continue to navigate through the results using the ''Next/Previous/Back to Query'' links after saving your results. When you return to the query ''any tickets which were edited'' will be displayed with italicized text. If one of the tickets was edited such that [[html(<span style="color: grey">it no longer matches the query criteria </span>)]] the text will also be greyed. Lastly, if '''a new ticket matching the query criteria has been created''', it will be shown in bold.
The query results can be refreshed and cleared of these status indicators by clicking the ''Update'' button again.
@@ -28,7 +28,6 @@
You may want to save some queries so that you can come back to them later. You can do this by making a link to the query from any Wiki page.
{{{
[query:status=new|assigned|reopened&version=1.0 Active tickets against 1.0]
-
}}}
Which is displayed as:
@@ -39,7 +38,6 @@
Alternatively, you can copy the query string of a query and paste that into the Wiki link, including the leading `?` character:
{{{
[query:?status=new&status=assigned&status=reopened&group=owner Assigned tickets by owner]
-
}}}
Which is displayed as:
@@ -47,7 +45,7 @@
=== Using the `[[TicketQuery]]` Macro ===
-The TicketQuery macro lets you display lists of tickets matching certain criteria anywhere you can use WikiFormatting.
+The [trac:TicketQuery TicketQuery] macro lets you display lists of tickets matching certain criteria anywhere you can use WikiFormatting.
Example:
{{{
@@ -62,7 +60,6 @@
A more compact representation without the ticket summaries is also available:
{{{
[[TicketQuery(version=0.6|0.7&resolution=duplicate, compact)]]
-
}}}
This is displayed as:
@@ -72,28 +69,38 @@
{{{
[[TicketQuery(version=0.6|0.7&resolution=duplicate, count)]]
-
}}}
This is displayed as:
[[TicketQuery(version=0.6|0.7&resolution=duplicate, count)]]
+=== Customizing the ''table'' format ===
+You can also customize the columns displayed in the table format (''format=table'') by using ''col=<field>'' - you can specify multiple fields and what order they are displayed by placing pipes (`|`) between the columns like below:
+
+{{{
+[[TicketQuery(max=3,status=closed,order=id,desc=1,format=table,col=resolution|summary|owner|reporter)]]
+}}}
+
+This is displayed as:
+[[TicketQuery(max=3,status=closed,order=id,desc=1,format=table,col=resolution|summary|owner|reporter)]]
+
=== Query Language ===
`query:` TracLinks and the `[[TicketQuery]]` macro both use a mini “query language” for specifying query filters. Basically, the filters are separated by ampersands (`&`). Each filter then consists of the ticket field name, an operator, and one or more values. More than one value are separated by a pipe (`|`), meaning that the filter matches any of the values.
The available operators are:
-|| '''=''' || the field content exactly matches the one of the values ||
-|| '''~=''' || the field content contains one or more of the values ||
-|| '''!^=''' || the field content starts with one of the values ||
-|| '''$=''' || the field content ends with one of the values ||
+|| '''`=`''' || the field content exactly matches the one of the values ||
+|| '''`~=`''' || the field content contains one or more of the values ||
+|| '''`^=`''' || the field content starts with one of the values ||
+|| '''`$=`''' || the field content ends with one of the values ||
All of these operators can also be negated:
-|| '''!=''' || the field content matches none of the values ||
-|| '''!~=''' || the field content does not contain any of the values ||
-|| '''!!^=''' || the field content does not start with any of the values ||
-|| '''!$=''' || the field content does not end with any of the values ||
+|| '''`!=`''' || the field content matches none of the values ||
+|| '''`!~=`''' || the field content does not contain any of the values ||
+|| '''`!^=`''' || the field content does not start with any of the values ||
+|| '''`!$=`''' || the field content does not end with any of the values ||
+
----
See also: TracTickets, TracReports, TracGuide
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracReports
^
|
@@ -241,7 +241,7 @@
If you have added custom fields to your tickets (a feature since v0.8, see TracTicketsCustomFields), you can write a SQL query to cover them. You'll need to make a join on the ticket_custom table, but this isn't especially easy.
-If you have tickets in the database ''before'' you declare the extra fields in trac.ini, there will be no associated data in the ticket_custom table. To get around this, use SQL's "LEFT OUTER JOIN" clauses. See TracIniReportCustomFieldSample for some examples.
+If you have tickets in the database ''before'' you declare the extra fields in trac.ini, there will be no associated data in the ticket_custom table. To get around this, use SQL's "LEFT OUTER JOIN" clauses. See [trac:TracIniReportCustomFieldSample TracIniReportCustomFieldSample] for some examples.
'''Note that you need to set up permissions in order to see the buttons for adding or editing reports.'''
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracRevisionLog
^
|
@@ -83,9 +83,9 @@
== Alternative Formats ==
-=== The ChangeLog Text ===
+=== The !ChangeLog Text ===
-At the bottom of the page, there's a ''ChangeLog'' link
+At the bottom of the page, there's a ''!ChangeLog'' link
that will show the range of revisions as currently shown,
but as a simple text, matching the usual conventions for
!ChangeLog files.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracStandalone
^
|
@@ -39,6 +39,8 @@
To exit the server on Windows, be sure to use {{{CTRL-BREAK}}} -- using {{{CTRL-C}}} will leave a Python process running in the background.
+When running as a Windows service using a utility such as [http://www.google.com/search?q=srvany.exe SRVANY], stopping or restarting the service will also leave a Python process running -- restart the system instead.
+
== Using Authentication ==
@@ -51,7 +53,7 @@
}}}
then for additional users:
{{{
-sudo htpasswd /var/www/html/.htpasswd-users username2
+sudo htpasswd /path/to/env/.htpasswd username2
}}}
then for starting the tracd:
{{{
@@ -94,9 +96,10 @@
for the project name:
{{{
$ tracd -p 8080 \
- --auth=*,/path/to/users.htdigest,mycompany.com \
+ --auth="*",/path/to/users.htdigest,mycompany.com \
/path/to/project1 /path/to/project2
}}}
+If using the `-s` parameter for serving a Trac environment from the root of a domain, one must use `*` for the project name
== How to set up an htdigest password file ==
@@ -111,7 +114,12 @@
{{{
#!python
from optparse import OptionParser
-import md5
+# The md5 module is deprecated in Python 2.5
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+realm = 'trac'
# build the options
usage = "usage: %prog [options]"
@@ -120,15 +128,18 @@
help="the username for whom to generate a password")
parser.add_option("-p", "--password",action="store", dest="password", type = "string",
help="the password to use")
+parser.add_option("-r", "--realm",action="store", dest="realm", type = "string",
+ help="the realm in which to create the digest")
(options, args) = parser.parse_args()
# check options
if (options.username is None) or (options.password is None):
parser.error("You must supply both the username and password")
+if (options.realm is not None):
+ realm = options.realm
# Generate the string to enter into the htdigest file
-realm = 'trac'
-kd = lambda x: md5.md5(':'.join(x)).hexdigest()
+kd = lambda x: md5(':'.join(x)).hexdigest()
print ':'.join((options.username, realm, kd([options.username, realm, options.password])))
}}}
@@ -171,10 +182,10 @@
In some situations when you choose to use tracd behind apache, you might experience issues with redirects, like being redirected to URLs with the wrong host or protocol. In this case (and only in this case), setting the `[trac] use_base_url_for_redirect` to `true` can help, as this will force Trac to use the value of `[trac] base_url` for doing the redirects.
=== Serving a different base path than / ===
-Tracd supports serving projects with different base urls then /<project>. The parameter name to change this is
+Tracd supports serving projects with different base urls than /<project>. The parameter name to change this is
{{{
tracd --base-path=/some/path
}}}
----
-See also: TracInstall, TracCgi, TracModPython, TracGuide
+See also: TracInstall, TracCgi, TracModPython, TracGuide, [trac:TracOnWindowsStandalone?version=13#RunningTracdasservice Running tracd.exe as a Windows service]
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracSupport
^
|
@@ -1,15 +1,15 @@
= Trac Support =
-Like in most [http://www.opensource.org/ open source projects], "free" Trac support is available primarily through the community itself, mainly through the [http://trac.edgewall.org/wiki/MailingList mailing list] and the project wiki.
+Like in most [http://www.opensource.org/ open source projects], "free" Trac support is available primarily through the community itself, mainly through the [trac:MailingList mailing list] and the project wiki.
-There is also an [http://trac.edgewall.org/wiki/IrcChannel IRC channel], where people might be able to help out. Much of the 'live' development discussions also happen there.
+There is also an [trac:IrcChannel IRC channel], where people might be able to help out. Much of the 'live' development discussions also happen there.
Before you start a new support query, make sure you've done the appropriate searching:
- * in the project's [http://trac.edgewall.org/wiki/TracFaq FAQ]
+ * in the project's [trac:TracFaq FAQ]
* in past messages to the Trac [http://blog.gmane.org/gmane.comp.version-control.subversion.trac.general?set_user_css=http%3A%2F%2Fwww.edgewall.com%2Fcss%2Fgmane.css&do_set_user_css=t Mailing List]
- * in the Trac ticket system, using either a [http://trac.edgewall.org/search?q=&ticket=on&wiki=on full search] or a [http://trac.edgewall.org/query?summary=~&keywords=~" ticket query].
+ * in the Trac ticket system, using either a [http://trac.edgewall.org/search?q=&ticket=on&wiki=on full search] or a [http://trac.edgewall.org/query?summary=~&keywords=~ ticket query].
-Please '''don't''' create a ticket in this Trac for asking a support question about Trac. Only use it when you face a ''real'' and ''new'' bug in Trac, and do so only after having read the NewTicketGuidelines. The more a bug report or enhancement request complies with those guidelines, the higher the chances are that it will be fixed or implemented promptly!
+Please '''don't''' create a ticket in this Trac for asking a support question about Trac. Only use it when you face a ''real'' and ''new'' bug in Trac, and do so only after having read the [trac:NewTicketGuidelines NewTicketGuidelines]. The more a bug report or enhancement request complies with those guidelines, the higher the chances are that it will be fixed or implemented promptly!
----
-See also: [http://trac.edgewall.org/wiki/MailingList MailingList], TracTroubleshooting, [http://trac.edgewall.org/wiki/CommercialServices CommercialServices]
+See also: [trac:MailingList MailingList], [trac:TracTroubleshooting TracTroubleshooting], [trac:CommercialServices CommercialServices]
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracSyntaxColoring
^
|
@@ -19,14 +19,14 @@
'''Note:''' Enscript supports a greater number of languages, however !SilverCity is generally faster since it is a library and isn't executed in an external process.
-=== About SilverCity ===
+=== About !SilverCity ===
!SilverCity uses the lexer from [http://www.scintilla.org/ Scintilla]. Scintilla supports more languages than !SilverCity implements. If you want to add a language to !SilverCity supported by Scintilla, it's not very difficult. See [http://trac.edgewall.org/wiki/SilverCityAddLanguage SilverCityAddLanguage] for some information how.
=== About Pygments ===
Starting with trac 0.11 [http://pygments.org/ pygments] will be the new default highlighter. It's a highlighting library implemented in pure python, very fast, easy to extend and [http://pygments.org/docs/ well documented]. While it does not support as many languages as Enscript or Scintilla the overall output quality is much better.
-To use pygments trac 0.11 you just have to install pygments 0.5.1 or higher. If you want to use it in trac 0.10 too you have to install the [http://trac-hacks.org/wiki/TracPygmentsPlugin TracPygmentsPlugin] from trac hacks. If you encounter any bugs, please file tickets regarding Pygments in [http://dev.pocoo.org/projects/pygments/ the pygments trac].
+To use pygments in trac 0.11 you just have to install pygments 0.6 or higher. If you want to use it in trac 0.10 too you have to install the [http://trac-hacks.org/wiki/TracPygmentsPlugin TracPygmentsPlugin] from trac hacks. If you encounter any bugs, please file tickets regarding Pygments in [http://dev.pocoo.org/projects/pygments/ the pygments trac].
It's very likely that the list below is outdated because the list of supported pygments lexers is growing weekly. Just have a look at the page of [http://pygments.org/docs/lexers/ supported lexers] on the pygments webpage.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracTickets
^
|
@@ -33,9 +33,9 @@
'''Note:''' Versions of Trac prior to 0.9 did not have the ''type'' field, but instead provided a ''severity'' field and different default values for the ''priority'' field. This change was done to simplify the ticket model by removing the somewhat blurry distinction between ''priority'' and ''severity''. However, the old model is still available if you prefer it: just add/modify the default values of the ''priority'' and ''severity'', and optionally hide the ''type'' field by removing all the possible values through [wiki:TracAdmin trac-admin].
-'''Note:''' the [wiki:TicketTypes type], [wiki:TicketComponent component], version, priority and severity fields can be managed with [wiki:TracAdmin trac-admin] or with the WebAdmin plugin.
+'''Note:''' the [trac:TicketTypes type], [trac:TicketComponent component], version, priority and severity fields can be managed with [wiki:TracAdmin trac-admin] or with the [trac:WebAdmin WebAdmin] plugin.
-'''Note:''' Description of the builtin ''priority'' values is available at [wiki:TicketTypes#Whyistheseverityfieldgone]
+'''Note:''' Description of the builtin ''priority'' values is available at [trac:TicketTypes#Whyistheseverityfieldgone TicketTypes]
== Changing and Commenting Tickets ==
@@ -85,6 +85,8 @@
To appear in the dropdown list, a user needs be registered with the project, ''i.e.'' a user session should exist in the database. Such an entry is automatically created in the database the first time the user submits a change in the project, for example when editing the user's details in the ''Settings'' page, or simply by authenticating if the user has a login. Also, the user must have `TICKET_MODIFY` [TracPermissions permissions].
+'''Note:''' See [http://pacopablo.com/wiki/pacopablo/blog/set-assign-to-drop-down Populating Assign To Drop Down] on how to add user entries at database level
+
== Preset Values for New Tickets ==
To create a link to the new-ticket form filled with preset values, you need to call the `/newticket?` URL with variable=value separated by &.
@@ -107,4 +109,4 @@
'''Example:''' ''/trac/newticket?summary=Compile%20Error&version=1.0&component=gui''[[BR]]
----
-See also: TracGuide, TracWiki, TracTicketsCustomFields, TracNotification, TracReports, TracQuery
+See also: TracGuide, TracWiki, TracTicketsCustomFields, TracNotification, TracReports, TracQuery
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracUnicode
^
|
@@ -9,7 +9,7 @@
default_charset = gbk
in trac.ini.
-You also must make sure that your [wiki:DatabaseBackend database backend] stores its data in UTF-8; otherwise strange things will happen.
+You also must make sure that your [trac:DatabaseBackend database backend] stores its data in UTF-8; otherwise strange things will happen.
To convert your database to UTF-8, the easiest way is to dump the database, convert the dump into UTF-8 and then import the converted dump back into the database.[[BR]]
You can use [http://www.gnu.org/software/libiconv/documentation/libiconv/iconv.1.html iconv] to convert the dump.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracUpgrade
^
|
@@ -13,8 +13,9 @@
Get the new version as described in TracInstall, or your operating system specific procedure.
-If you do a manual (not operating system specific) upgrade, you may also later on want to remove the existing Trac code by deleting the `trac` directory from the Python `lib/site-packages` directory.
+If you do a manual (not operating system specific) upgrade, you should also stop any running Trac server before the installation. Doing "hot" upgrades is not advised, especially not on Windows ([trac:ticket:7625 #7265]).
+You may also want to remove the pre-existing Trac code by deleting the `trac` directory from the Python `lib/site-packages` directory, or remove Trac .eggs from former versions.
The location of the site-packages directory depends on the operating system, and the location in which Python was installed. However, the following locations are common:
* If you’re using Linux: /usr/lib/python2.X/site-packages
* If you’re using Windows: C:\Python2.X\lib\site-packages
@@ -22,6 +23,8 @@
You may also want to remove the Trac `cgi-bin`, `htdocs`, `templates` and `wiki-default` directories that are commonly found in a directory called `share/trac` (the exact location depends on your platform).
+This cleanup is not mandatory, but it makes it easier to troubleshoot issues later on, as you won't waste your time looking at code or templates from a previous release that are not being used anymore... As usual, make a backup before actually deleting things.
+
If you had the webadmin plugin installed, you can now uninstall it as it is now part of the Trac code base.
=== Upgrade the Trac Environment ===
@@ -49,8 +52,20 @@
Note that this procedure will of course leave your `WikiStart` page intact.
+=== Site Templates ===
+The templating engine has changed in 0.11, please look at TracInterfaceCustomization for more information.
+
=== Trac Macros, Plugins ===
-The Trac macros will need to be adapted, as the old-style wiki-macros are not supported anymore (due to the drop of ClearSilver and the HDF); they need to be converted to the new-style macros, see WikiMacros. When they are converted to the new style, they need to be placed into the plugins directory instead and not wiki-macros, which is no longer scanned for macros or plugins.
+The Trac macros will need to be adapted, as the old-style wiki-macros are not supported anymore (due to the drop of [trac:ClearSilver ClearSilver] and the HDF); they need to be converted to the new-style macros, see WikiMacros. When they are converted to the new style, they need to be placed into the plugins directory instead and not wiki-macros, which is no longer scanned for macros or plugins.
+
+=== For CGI users ===
+
+For those who run Trac under the CGI environment, run this command in order to obtain the trac.cgi file:
+{{{
+trac-admin /path/to/env deploy /deploy/directory/path
+}}}
+
+This will create a deploy directory with the following two subdirectories: `cgi-bin` and `htdocs`. Move those directories to your environment directory, and then update your Apache configuration file `httpd.conf` with this new `trac.cgi` location.
=== Restart the Web Server ===
If you are not running [wiki:TracCgi CGI], reload the new Trac code by restarting your web server.
@@ -75,7 +90,13 @@
== Older Versions ==
-For upgrades from former versions refer to wiki:0.10/TracUpgrade.
+For upgrades from versions older than Trac 0.10, refer first to trac:wiki:0.10/TracUpgrade.
+
+Note that downgrading from Trac 0.11 to Trac 0.10.4 or 0.10.5 is easy, but has to be done manually, e.g.
+{{{
+$ sqlite3 db/trac.db "update system set value=20 where name='database_version'"
+}}}
+(upgrade can be redone the normal way later on)
-----
See also: TracGuide, TracInstall
\ No newline at end of file
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/TracWorkflow
^
|
@@ -13,7 +13,7 @@
[[Image(htdocs:../common/guide/original-workflow.png)]]
There are some significant "warts" in this; such as accepting a ticket sets it to 'assigned' state, and assigning a ticket sets it to 'new' state. Perfectly obvious, right?
-So you will probably want to migrate to "basic" workflow; `contrib/workflow/migrate_original_to_basic.py` may be helpful.
+So you will probably want to migrate to "basic" workflow; [trac:source:trunk/contrib/workflow/migrate_original_to_basic.py contrib/workflow/migrate_original_to_basic.py] may be helpful.
=== Environments created with 0.11 ===
When a new environment is created, a default workflow is configured in your trac.ini. This workflow is the basic workflow (described in `basic-workflow.ini`), which is somewhat different from the workflow of the 0.10 releases.
@@ -24,7 +24,9 @@
== Additional Ticket Workflows ==
-There are several example workflows provided in the Trac source tree; look in `contrib/workflow` for `.ini` config sections. One of those may be a good match for what you want. They can be pasted into the `[ticket-workflow]` section of your `trac.ini` file.
+There are several example workflows provided in the Trac source tree; look in [trac:source:trunk/contrib/workflow contrib/workflow] for `.ini` config sections. One of those may be a good match for what you want. They can be pasted into the `[ticket-workflow]` section of your `trac.ini` file.
+
+Here are some [http://trac.edgewall.org/wiki/WorkFlow/Examples diagrams] of the above examples.
== Basic Ticket Workflow Customization ==
@@ -109,6 +111,63 @@
pass.set_resolution = fixed
}}}
+== Example: Add simple optional generic review state ==
+
+Sometimes Trac is used in situations where "testing" can mean different things to different people so you may want to create an optional workflow state that is between the default workflow's `assigned` and `closed` states, but does not impose implementation-specific details. The only new state you need to add for this is a `reviewing` state. A ticket may then be "submitted for review" from any state that it can be reassigned. If a review passes, you can re-use the `resolve` action to close the ticket, and if it fails you can re-use the `reassign` action to push it back into the normal workflow.
+
+The new `reviewing` state along with its associated `review` action looks like this:
+
+{{{
+review = new,assigned,reopened -> reviewing
+review.operations = set_owner
+review.permissions = TICKET_MODIFY
+}}}
+
+Then, to integrate this with the default Trac 0.11 workflow, you also need to add the `reviewing` state to the `accept` and `resolve` actions, like so:
+
+{{{
+accept = new,reviewing -> assigned
+[…]
+resolve = new,assigned,reopened,reviewing -> closed
+}}}
+
+Optionally, you can also add a new action that allows you to change the ticket's owner without moving the ticket out of the `reviewing` state. This enables you to reassign review work without pushing the ticket back to the `new` status.
+
+{{{
+reassign_reviewing = reviewing -> *
+reassign_reviewing.name = reassign review
+reassign_reviewing.operations = set_owner
+reassign_reviewing.permissions = TICKET_MODIFY
+}}}
+
+The full `[ticket-workflow]` configuration will thus look like this:
+
+{{{
+[ticket-workflow]
+accept = new,reviewing -> assigned
+accept.operations = set_owner_to_self
+accept.permissions = TICKET_MODIFY
+leave = * -> *
+leave.default = 1
+leave.operations = leave_status
+reassign = new,assigned,reopened -> new
+reassign.operations = set_owner
+reassign.permissions = TICKET_MODIFY
+reopen = closed -> reopened
+reopen.operations = del_resolution
+reopen.permissions = TICKET_CREATE
+resolve = new,assigned,reopened,reviewing -> closed
+resolve.operations = set_resolution
+resolve.permissions = TICKET_MODIFY
+review = new,assigned,reopened -> reviewing
+review.operations = set_owner
+review.permissions = TICKET_MODIFY
+reassign_reviewing = reviewing -> *
+reassign_reviewing.operations = set_owner
+reassign_reviewing.name = reassign review
+reassign_reviewing.permissions = TICKET_MODIFY
+}}}
+
== Example: Limit the resolution options for a new ticket ==
The above resolve_new operation allows you to set the possible resolutions for a new ticket. By modifying the existing resolve action and removing the new status from before the `->` we then get two resolve actions. One with limited resolutions for new tickets, and then the regular one once a ticket is accepted.
@@ -131,9 +190,13 @@
But if even that is not enough, you can disable the !ConfigurableTicketWorkflow component and create a plugin that completely replaces it.
+== Adding Workflow States to Milestone Progress Bars ==
+
+If you add additional states to your workflow, you may want to customize your milestone progress bars as well. See [TracIni#milestone-groups-section TracIni].
+
== some ideas for next steps ==
-New enhancement ideas for the workflow system should be filed as enhancement tickets against the `ticket system` component. If desired, add a single-line link to that ticket here.
+New enhancement ideas for the workflow system should be filed as enhancement tickets against the `ticket system` component. If desired, add a single-line link to that ticket here. Also look at the [th:wiki:AdvancedTicketWorkflowPlugin] as it provides experimental operations.
If you have a response to the comments below, create an enhancement ticket, and replace the description below with a link to the ticket.
@@ -141,15 +204,15 @@
* '''preops''': automatic, before entering the state/activity
* '''postops''': automatic, when leaving the state/activity
* '''actions''': can be chosen by the owner in the list at the bottom, and/or drop-down/pop-up together with the default actions of leaving the node on one of the arrows.
-This appears to add complexity without adding functionality; please provide a detailed example where these additions allow something currently impossible to implement.
+''This appears to add complexity without adding functionality; please provide a detailed example where these additions allow something currently impossible to implement.''
* operations could be anything: sum up the time used for the activity, or just write some statistical fields like
-A workflow plugin can add an arbitrary workflow operation, so this is already possible.
+''A workflow plugin can add an arbitrary workflow operation, so this is already possible.''
* set_actor should be an operation allowing to set the owner, e.g. as a "preop":
* either to a role, a person
* entered fix at define time, or at run time, e.g. out of a field, or select.
-This is either duplicating the existing `set_owner` operation, or needs to be clarified.
+''This is either duplicating the existing `set_owner` operation, or needs to be clarified.''
* Actions should be selectable based on the ticket type (different Workflows for different tickets)
-This is becoming a frequent request, with clear usecases. The closest the current implementation will allow is to have a plugin provide a `triage` action that sets the next state based on the ticket type, so a `new` ticket would move to `new_task`, `new_defect`, etc., and the workflow graph would separate at that point.
+''Look into the [th:wiki:AdvancedTicketWorkflowPlugin]'s `triage` operation.''
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/WikiMacros
^
|
@@ -35,12 +35,14 @@
== Developing Custom Macros ==
Macros, like Trac itself, are written in the [http://python.org/ Python programming language].
-For more information about developing macros, see the [wiki:TracDev development resources] on the main project site.
+For more information about developing macros, see the [trac:TracDev development resources] on the main project site.
== Implementation ==
-Here are 2 simple examples on how to create a Macro with [wiki:0.11 Trac 0.11] have a look at source:trunk/sample-plugins/Timestamp.py for an example that shows the difference between old style and new style macros and also source:trunk/wiki-macros/README which provides a little more insight about the transition.
+Here are 2 simple examples showing how to create a Macro with Trac 0.11.
+
+Also, have a look at [trac:source:tags/trac-0.11/sample-plugins/Timestamp.py Timestamp.py] for an example that shows the difference between old style and new style macros and at the [trac:source:tags/trac-0.11/wiki-macros/README macros/README] which provides a little more insight about the transition.
=== Macro without arguments ===
It should be saved as `TimeStamp.py` as Trac will use the module name as the Macro name
@@ -54,7 +56,7 @@
from trac.util.datefmt import format_datetime, utc
from trac.wiki.macros import WikiMacroBase
-class TimestampMacro(WikiMacroBase):
+class TimeStampMacro(WikiMacroBase):
"""Inserts the current time (in seconds) into the wiki page."""
revision = "$Rev$"
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/WikiRestructuredText
^
|
@@ -9,6 +9,8 @@
Note that to activate RST support in Trac, the python docutils package must be installed.
If not already available on your operating system, you can download it at the [http://docutils.sourceforge.net/rst.html RST Website].
+Install docutils using `easy_install docutils`. Do not use the package manager of your OS (e.g. `apt-get install python-docutils`), because Trac will not find docutils then.
+
=== More information on RST ===
* reStructuredText Website -- http://docutils.sourceforge.net/rst.html
@@ -86,7 +88,7 @@
=== Wiki Macros in reStructuredText ===
For doing [WikiMacros Wiki Macros] in ReST you use the same directive as for syntax highlighting i.e
-code-block. To work you must use a version of trac that has #801 applied.
+code-block. To work you must use a version of trac that has [trac:ticket:801 #801] applied.
=== Wiki Macro Example ===
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/default-pages/WikiStart
^
|
@@ -1,4 +1,4 @@
-= Welcome to Trac 0.11.1 =
+= Welcome to Trac 0.11.2.1 =
Trac is a '''minimalistic''' approach to '''web-based''' management of
'''software projects'''. Its goal is to simplify effective tracking and handling of software issues, enhancements and overall progress.
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/formatter.py
^
|
@@ -26,7 +26,6 @@
from genshi.builder import tag, Element
from genshi.core import Stream, Markup, escape
-from genshi.filters import HTMLSanitizer
from genshi.input import HTMLParser, ParseError
from genshi.util import plaintext
@@ -38,6 +37,7 @@
from trac.wiki.parser import WikiParser
from trac.util.text import shorten_line, to_unicode, \
unicode_quote, unicode_quote_plus
+from trac.util.html import TracHTMLSanitizer
from trac.util.translation import _
__all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline',
@@ -62,6 +62,8 @@
class WikiProcessor(object):
_code_block_re = re.compile('^<div(?:\s+class="([^"]+)")?>(.*)</div>$')
+ _block_elem_re = re.compile(r'^\s*<(?:div|table)(?:\s+[^>]+)?>',
+ re.I | re.M)
def __init__(self, formatter, name, args={}):
"""Find the processor by name
@@ -86,8 +88,7 @@
'span': self._span_processor,
'Span': self._span_processor}
- self._sanitizer = HTMLSanitizer(safe_attrs=HTMLSanitizer.SAFE_ATTRS |
- set(['style']))
+ self._sanitizer = TracHTMLSanitizer()
self.processor = builtin_processors.get(name)
if not self.processor:
@@ -193,14 +194,15 @@
elif tagname == 'table':
interrupt_paragraph = True
else:
+ # FIXME: do something smarter for Streams
text = to_unicode(text)
- match = re.match(self._code_block_re, unicode(text))
+ match = re.match(self._code_block_re, text)
if match:
if match.group(1) and 'code' in match.group(1):
content_for_span = match.group(2)
else:
interrupt_paragraph = True
- elif text.startswith('<table'):
+ elif re.match(self._block_elem_re, text):
interrupt_paragraph = True
if content_for_span:
text = tag.span(class_='code-block')(*content_for_span)
@@ -1085,19 +1087,25 @@
def format_to(env, flavor, context, wikidom, **options):
+ if flavor is None:
+ flavor = context.get_hint('wiki_flavor', 'html')
if flavor == 'oneliner':
return format_to_oneliner(env, context, wikidom, **options)
else:
return format_to_html(env, context, wikidom, **options)
-def format_to_html(env, context, wikidom, escape_newlines=False):
+def format_to_html(env, context, wikidom, escape_newlines=None):
if not wikidom:
return Markup()
+ if escape_newlines is None:
+ escape_newlines = context.get_hint('preserve_newlines', False)
return HtmlFormatter(env, context, wikidom).generate(escape_newlines)
-def format_to_oneliner(env, context, wikidom, shorten=False):
+def format_to_oneliner(env, context, wikidom, shorten=None):
if not wikidom:
return Markup()
+ if shorten is None:
+ shorten = context.get_hint('shorten_lines', False)
return InlineHtmlFormatter(env, context, wikidom).generate(shorten)
def extract_link(env, context, wikidom):
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/parser.py
^
|
@@ -98,9 +98,10 @@
# * list
r"(?P<list>^(?P<ldepth>\s+)(?:[-*]|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )",
# definition::
- r"(?P<definition>^\s+((?:%s[^%s]*%s|%s.*?%s|[^%s%s:]|:[^:])+::)(?:\s+|$))"
+ r"(?P<definition>^\s+((?:%s[^%s]*%s|%s(?:%s{,2}[^%s])*?%s|[^%s%s:]|:[^:])+::)(?:\s+|$))"
% (INLINE_TOKEN, INLINE_TOKEN, INLINE_TOKEN,
- STARTBLOCK_TOKEN, ENDBLOCK_TOKEN, INLINE_TOKEN, STARTBLOCK[0]),
+ STARTBLOCK_TOKEN, ENDBLOCK[0], ENDBLOCK[0], ENDBLOCK_TOKEN,
+ INLINE_TOKEN, STARTBLOCK[0]),
# (leading space)
r"(?P<indent>^(?P<idepth>\s+)(?=\S))",
# || table ||
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/templates/wiki_view.html
^
|
@@ -19,6 +19,13 @@
<body>
<div id="content" class="wiki">
+ <p class="path" py:if="'/' in page.name" py:with="parts = page.name.split('/')">
+ <py:for each="idx, part in enumerate(parts)"><a
+ class="pathentry" title="View ${'/'.join(parts[:idx + 1])}" href="${href.wiki(*parts[:idx + 1])}">${part}</a><span
+ class="pathentry sep" py:if="idx != len(parts) - 1">/</span></py:for>
+ <br style="clear: both" />
+ </p>
+
<py:if test="version">
<table id="info" summary="Revision info">
<tbody>
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/tests/formatter.py
^
|
@@ -29,6 +29,14 @@
def expand_macro(self, formatter, name, content):
return '<div>Hello World, args = %s</div>' % content
+class TableHelloWorldMacro(WikiMacroBase):
+ """A dummy macro returning a table block, used by the unit test."""
+
+ def expand_macro(self, formatter, name, content):
+ return """
+ <table><tr><th>Hello World</th><td>%s</td></tr></table>
+ """ % content
+
class DivCodeMacro(WikiMacroBase):
"""A dummy macro returning a div block, used by the unit test."""
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/tests/wiki-tests.txt
^
|
@@ -652,6 +652,16 @@
</p>
------------------------------
[[DivHelloWorld(...)]]
+============================== Macro returning a <table> preceeded by space
+[[TableHelloWorld(hej hopp)]]
+------------------------------
+<p>
+</p>
+ <table><tr><th>Hello World</th><td>hej hopp</td></tr></table>
+ <p>
+</p>
+------------------------------
+[[TableHelloWorld(...)]]
============================== Macro returning a <div class="...code...">
[[DivCode(hej hopp)]]
------------------------------
@@ -1034,6 +1044,16 @@
</blockquote>
------------------------------
term::definition
+============================== Pathological definition list counter example with block quotes
+ {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}}
+------------------------------
+<blockquote>
+<p>
+<tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt>
+</p>
+</blockquote>
+------------------------------
+<tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt>
============================== Definition list + escaped definition list
complex topic:: multiline
`not:: a dl`
|
[-]
[+]
|
Changed |
Trac-0.11.2.1.tar.gz/trac/wiki/web_ui.py
^
|
@@ -24,6 +24,7 @@
from genshi.builder import tag
from trac.attachment import AttachmentModule
+from trac.config import IntOption
from trac.core import *
from trac.mimeview.api import Mimeview, IContentConverter, Context
from trac.perm import IPermissionRequestor
@@ -40,7 +41,7 @@
INavigationContributor, ITemplateProvider
from trac.web import IRequestHandler
from trac.wiki.api import IWikiPageManipulator, WikiSystem
-from trac.wiki.formatter import format_to_oneliner
+from trac.wiki.formatter import format_to
from trac.wiki.model import WikiPage
class InvalidWikiPage(TracError):
@@ -58,6 +59,9 @@
page_manipulators = ExtensionPoint(IWikiPageManipulator)
+ max_size = IntOption('wiki', 'max_size', 262144,
+ """Maximum allowed wiki page size in bytes. (''since 0.11.2'')""")
+
PAGE_TEMPLATES_PREFIX = 'PageTemplates/'
DEFAULT_PAGE_TEMPLATE = 'DefaultPage'
@@ -96,7 +100,7 @@
# IRequestHandler methods
def match_request(self, req):
- match = re.match(r'^/wiki(?:/(.*)|$)', req.path_info)
+ match = re.match(r'/wiki(?:/(.+))?$', req.path_info)
if match:
if match.group(1):
req.args['page'] = match.group(1)
@@ -173,6 +177,14 @@
def _validate(self, req, page):
valid = True
+
+ # Validate page size
+ if len(req.args.get('text', '')) > self.max_size:
+ add_warning(req, _('The wiki page is too long (must be less '
+ 'than %(num)s characters)',
+ num=self.max_size))
+ valid = False
+
# Give the manipulators a pass at post-processing the page
for manipulator in self.page_manipulators:
for field, message in manipulator.validate_wiki_page(req, page):
@@ -264,9 +276,8 @@
page.save(get_reporter_id(req, 'author'),
req.args.get('comment'),
req.remote_addr)
- not_modified = False
req.redirect(get_resource_url(self.env, page.resource, req.href,
- version=page.version))
+ version=None))
except TracError:
add_warning(req, _("Page not modified, showing latest version."))
return self._render_view(req, page)
@@ -507,8 +518,14 @@
req.href.wiki(page.name, version=prev_version),
_('Version %(num)s', num=prev_version))
- add_link(req, 'up', req.href.wiki(page.name, version=None),
- _('View Latest Version'))
+ parent = None
+ if version:
+ add_link(req, 'up', req.href.wiki(page.name, version=None),
+ _('View latest version'))
+ elif '/' in page.name:
+ parent = page.name[:page.name.rindex('/')]
+ add_link(req, 'up', req.href.wiki(parent, version=None),
+ _("View parent page"))
if next_version:
add_link(req, 'next',
@@ -522,6 +539,8 @@
req.href.wiki(page.name, action='diff',
version=page.version))
else:
+ if parent:
+ add_ctxtnav(req, _('Up'), req.href.wiki(parent))
self._wiki_ctxtnav(req, page)
context = Context.from_request(req, page.resource)
@@ -580,10 +599,8 @@
return tag(tag.em(get_resource_name(self.env, wiki_page)),
wiki_page.version > 1 and ' edited' or ' created')
elif field == 'description':
- if self.config['timeline'].getbool('abbreviated_messages'):
- comment = shorten_line(comment)
- markup = format_to_oneliner(self.env, context(resource=wiki_page),
- comment)
+ markup = format_to(self.env, None, context(resource=wiki_page),
+ comment)
if wiki_page.version > 1:
diff_href = context.href.wiki(
wiki_page.id, version=wiki_page.version, action='diff')
|