keithsalisbury-subtrac 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +56 -0
- data/VERSION.yml +4 -0
- data/bin/subtrac +40 -0
- data/lib/subtrac.rb +245 -0
- data/lib/subtrac/common/clients/index.wsgi +89 -0
- data/lib/subtrac/common/favicon.ico +0 -0
- data/lib/subtrac/common/images/trac/banner_bg.jpg +0 -0
- data/lib/subtrac/common/images/trac/bar_bg.gif +0 -0
- data/lib/subtrac/common/images/trac/footer_back.png +0 -0
- data/lib/subtrac/common/images/trac/main_bg.gif +0 -0
- data/lib/subtrac/common/images/trac/saint_logo_small.png +0 -0
- data/lib/subtrac/common/static/404.html +14 -0
- data/lib/subtrac/common/styles/trac.css +222 -0
- data/lib/subtrac/common/trac.ini +178 -0
- data/lib/subtrac/config/config.yml +54 -0
- data/lib/subtrac/passwords +1 -0
- data/lib/subtrac/shared/trac.ini +178 -0
- data/lib/subtrac/templates/location.erb +16 -0
- data/lib/subtrac/templates/projects/blank/svn/branches/README +0 -0
- data/lib/subtrac/templates/projects/blank/svn/tags/README +0 -0
- data/lib/subtrac/templates/projects/blank/svn/trunk/README +0 -0
- data/lib/subtrac/templates/projects/blank/trac/wiki/WikiStart +57 -0
- data/lib/subtrac/templates/projects/new/svn/trunk/trac/wiki/WikiStart +46 -0
- data/lib/subtrac/templates/projects/new/trac/wiki/WikiStart +23 -0
- data/lib/subtrac/templates/projects/trac_theme/svn/trunk/index/index.html +22 -0
- data/lib/subtrac/templates/projects/trac_theme/svn/trunk/templates/layout.html +56 -0
- data/lib/subtrac/templates/projects/trac_theme/svn/trunk/templates/site.html +27 -0
- data/lib/subtrac/templates/projects/trac_theme/svn/trunk/templates/theme.html +86 -0
- data/lib/subtrac/templates/projects/trac_theme/trac/wiki/WikiStart +4 -0
- data/lib/subtrac/templates/trac.erb +25 -0
- data/lib/subtrac/templates/vhost.erb +35 -0
- data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/advancedworkflow/__init__.py +0 -0
- data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/advancedworkflow/controller.py +419 -0
- data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/setup.cfg +3 -0
- data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/setup.py +20 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/__init__.py +0 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/action.py +28 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/action_email.py +168 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/action_zendesk_forum.py +137 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/admin.py +91 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/api.py +199 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/client.py +105 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/events.py +287 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/eventsadmin.py +71 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/htdocs/clients.css +4 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/model.py +135 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/processor.py +70 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/reportmanager.py +142 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/reports.py +231 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/summary.py +27 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/summary_milestone.py +152 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/summary_ticketchanges.py +160 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/templates/admin_client_events.html +124 -0
- data/lib/subtrac/trac-plugins/clientsplugin/clients/templates/admin_clients.html +134 -0
- data/lib/subtrac/trac-plugins/clientsplugin/cron/changes.xslt +132 -0
- data/lib/subtrac/trac-plugins/clientsplugin/cron/run-client-event +97 -0
- data/lib/subtrac/trac-plugins/clientsplugin/cron/summary.xslt +161 -0
- data/lib/subtrac/trac-plugins/clientsplugin/setup.py +43 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/__init__.py +4 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/burndownchart.py +273 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/hoursinplaceeditor.py +44 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/hoursremaining.py +36 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery-1.2.3.min.js +32 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery.jeditable.js +409 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery.jeditable.mini.js +30 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/templates/edithours.html +53 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/burndownchart.py +181 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/hoursremaining.py +66 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/workloadchart.py +47 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/utils.py +93 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/workloadchart.py +86 -0
- data/lib/subtrac/trac-plugins/estimationtoolsplugin/setup.py +20 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/SumRollups.js +23 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/adw_tracdb.py +128 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/git-post-receive +40 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/trac-post-commit.py +285 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/trac_billing.py +173 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/utils/__init__.py +0 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/utils/mail.py +164 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/setup.py +69 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/__init__.py +1 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/api.py +292 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/blackmagic.py +172 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/dbhelper.py +178 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/billingplugin.css +25 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/field_disabler.js +6 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/formatDate.js +356 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/tip_centerwindow.js +100 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/tip_followscroll.js +84 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/wz_tooltip.js +1149 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/linkifyer.js +119 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/query.js +73 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/ticket.js +165 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/query_webui.py +28 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reportmanager.py +221 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reports.py +675 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reports_filter.py +150 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/statuses.py +25 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/tande_filters.py +131 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/templates/billing.cs +84 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/templates/billing.html +104 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_daemon.py +194 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_policy.py +62 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_webui.py +28 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/usermanual.py +127 -0
- data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/webui.py +129 -0
- data/lib/subtrac/trac-plugins/worklogplugin/setup.py +29 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/__init__.py +1 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/api.py +187 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jqModal.css +40 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jqModal.js +67 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jquery.mousewheel.pack.js +12 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jquery.timeentry.pack.js +7 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/tracWorklog.js +40 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/ui.datepicker.css +208 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/ui.datepicker.js +1439 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/work.png +0 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/work.xcf +0 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/worklogplugin.css +80 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/workstart.png +0 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/workstop.png +0 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/manager.py +336 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/reports.py +598 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog.html +45 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_stop.html +70 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_user.html +40 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_webadminui.html +59 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/ticket_daemon.py +33 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/ticket_filter.py +153 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/timeline_hook.py +96 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/usermanual.py +29 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/util.py +31 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/webadminui.py +47 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/webui.py +174 -0
- data/lib/subtrac/trac-plugins/worklogplugin/worklog/xmlrpc.py +73 -0
- data/lib/subtrac/version.rb +4 -0
- metadata +191 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
<!DOCTYPE html
|
2
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
3
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
4
|
+
<html xmlns="http://www.w3.org/1999/xhtml"
|
5
|
+
xmlns:xi="http://www.w3.org/2001/XInclude"
|
6
|
+
xmlns:py="http://genshi.edgewall.org/">
|
7
|
+
<xi:include href="admin.html" />
|
8
|
+
<head>
|
9
|
+
<title>Clients</title>
|
10
|
+
<style type="text/css">
|
11
|
+
p.contextual { margin-top:0; margin-bottom:2em }
|
12
|
+
</style>
|
13
|
+
</head>
|
14
|
+
|
15
|
+
<body>
|
16
|
+
<h2>Manage Clients</h2>
|
17
|
+
|
18
|
+
<py:choose test="view">
|
19
|
+
<form py:when="'detail'" class="mod" id="modclient" method="post">
|
20
|
+
<fieldset>
|
21
|
+
<legend>Modify Client:</legend>
|
22
|
+
<div class="field">
|
23
|
+
<label>Name:<br />
|
24
|
+
<input type="text" name="name" value="$client.name"/></label>
|
25
|
+
</div>
|
26
|
+
<div class="field">
|
27
|
+
<fieldset class="iefix">
|
28
|
+
<label for="description">
|
29
|
+
Description (you may use
|
30
|
+
<a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a>
|
31
|
+
here):
|
32
|
+
</label>
|
33
|
+
<p>
|
34
|
+
<textarea id="description" name="description" class="wikitext"
|
35
|
+
rows="6" cols="60">
|
36
|
+
$client.description</textarea>
|
37
|
+
</p>
|
38
|
+
</fieldset>
|
39
|
+
</div>
|
40
|
+
<div py:if="42==1" class="field">
|
41
|
+
<label>Currency:<br />
|
42
|
+
<input type="text" name="currency" value="$client.currency"/></label>
|
43
|
+
<p class="contextual help">Purely cosmetic and for display purposes only. The currency symbol to use for this client.</p>
|
44
|
+
</div>
|
45
|
+
<div class="field">
|
46
|
+
<label>Default Charge Rate:<br />
|
47
|
+
<input type="text" name="default_rate" value="$client.default_rate"/></label>
|
48
|
+
<p class="contextual help">The default numeric hourly rate for this client (will be copied to the ticket on creation)</p>
|
49
|
+
</div>
|
50
|
+
</fieldset>
|
51
|
+
|
52
|
+
<py:for each="event in events">
|
53
|
+
<py:for each="options in (event.summary_client_options, event.action_client_options)">
|
54
|
+
<fieldset py:if="options">
|
55
|
+
<py:with vars="field = options==event.summary_options and 'summary' or 'action'">
|
56
|
+
<legend py:if="'summary'==field">Client Specific Summary Options for $event.name</legend>
|
57
|
+
<legend py:if="'action'==field">Client Specific Action Options for $event.name</legend>
|
58
|
+
<div py:for="option in options.values()" class="field">
|
59
|
+
<label>$option.name</label><br />
|
60
|
+
<py:choose test="option.type">
|
61
|
+
<textarea py:when="'large'" name="${field}-option-${event.md5}-${option.md5}" rows="10" cols="70">$option.value</textarea>
|
62
|
+
<input py:when="'small'" name="${field}-option-${event.md5}-${option.md5}" type="text" size="5" value="$option.value" />
|
63
|
+
<select py:when="'list'" name="${field}-option-${event.md5}-${option.md5}">
|
64
|
+
<option py:for="val in option.vals" selected="${val == option.value and 'selected' or None}">$val</option>
|
65
|
+
</select>
|
66
|
+
<input py:otherwise="" name="${field}-option-${event.md5}-${option.md5}" type="text" size="60" value="$option.value" />
|
67
|
+
</py:choose>
|
68
|
+
<p class="help">$option.description</p>
|
69
|
+
</div>
|
70
|
+
</py:with>
|
71
|
+
</fieldset>
|
72
|
+
</py:for>
|
73
|
+
</py:for>
|
74
|
+
|
75
|
+
<div class="buttons">
|
76
|
+
<input type="submit" name="cancel" value="Cancel" />
|
77
|
+
<input type="submit" name="save" value="Save" />
|
78
|
+
</div>
|
79
|
+
</form>
|
80
|
+
|
81
|
+
<py:otherwise>
|
82
|
+
<form class="addnew" id="addclient" method="post">
|
83
|
+
<fieldset>
|
84
|
+
<legend>Add Client:</legend>
|
85
|
+
<div class="field">
|
86
|
+
<label>Name:<br /><input type="text" name="name" /></label>
|
87
|
+
</div>
|
88
|
+
<div class="buttons">
|
89
|
+
<input type="submit" name="add" value="Add"/>
|
90
|
+
</div>
|
91
|
+
</fieldset>
|
92
|
+
</form>
|
93
|
+
|
94
|
+
<py:choose>
|
95
|
+
<form py:when="clients" method="POST">
|
96
|
+
<table class="listing" id="clientlist">
|
97
|
+
<thead>
|
98
|
+
<tr><th class="sel"> </th>
|
99
|
+
<th>Name</th><th>Default</th>
|
100
|
+
</tr>
|
101
|
+
</thead>
|
102
|
+
<tbody>
|
103
|
+
<tr py:for="client in clients">
|
104
|
+
<td class="sel"><input type="checkbox" name="sel" value="$client.name" /></td>
|
105
|
+
<td class="name">
|
106
|
+
<a href="${panel_href(client.name)}">$client.name</a>
|
107
|
+
</td>
|
108
|
+
<td class="default">
|
109
|
+
<input type="radio" name="default" value="$client.name"
|
110
|
+
checked="${client.name==default or None}" />
|
111
|
+
</td>
|
112
|
+
</tr>
|
113
|
+
</tbody>
|
114
|
+
</table>
|
115
|
+
<div class="buttons">
|
116
|
+
<input type="submit" name="remove" value="Remove selected items" />
|
117
|
+
<input type="submit" name="apply" value="Apply changes" />
|
118
|
+
</div>
|
119
|
+
<p class="help">
|
120
|
+
You can remove all items from this list to completely hide this
|
121
|
+
field from the user interface.
|
122
|
+
</p>
|
123
|
+
</form>
|
124
|
+
|
125
|
+
<p py:otherwise="" class="help">
|
126
|
+
As long as you don't add any items to the list, this field
|
127
|
+
will remain completely hidden from the user interface.
|
128
|
+
</p>
|
129
|
+
</py:choose>
|
130
|
+
</py:otherwise>
|
131
|
+
</py:choose>
|
132
|
+
</body>
|
133
|
+
|
134
|
+
</html>
|
@@ -0,0 +1,132 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
|
3
|
+
<xsl:stylesheet
|
4
|
+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
5
|
+
version="1.0">
|
6
|
+
|
7
|
+
<xsl:output method="html" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
|
8
|
+
<xsl:decimal-format name="GBP" decimal-separator="." grouping-separator=","/>
|
9
|
+
|
10
|
+
<!-- Match the root of the XML render the three views -->
|
11
|
+
<xsl:template match="/">
|
12
|
+
<xsl:choose>
|
13
|
+
<xsl:when test="$view='html'">
|
14
|
+
<!-- Should return HTML as you see fit -->
|
15
|
+
<xsl:call-template name="html"/>
|
16
|
+
</xsl:when>
|
17
|
+
<xsl:when test="$view='images'">
|
18
|
+
<!--
|
19
|
+
Should return a list of images to embed in the following format:
|
20
|
+
|
21
|
+
<images>
|
22
|
+
<img id="myimage" src="/local/path/to/image"/>
|
23
|
+
</images>
|
24
|
+
|
25
|
+
Where "myimage" is references in your HTML image as <img src="cid:myimage" />
|
26
|
+
-->
|
27
|
+
<xsl:call-template name="images"/>
|
28
|
+
</xsl:when>
|
29
|
+
<xsl:otherwise>
|
30
|
+
<!-- The plain text portion of the email -->
|
31
|
+
<xsl:call-template name="plain"/>
|
32
|
+
</xsl:otherwise>
|
33
|
+
</xsl:choose>
|
34
|
+
</xsl:template>
|
35
|
+
|
36
|
+
<!-- Simple (cop-out) implementation of a plain text message -->
|
37
|
+
<xsl:template name="plain">
|
38
|
+
<xsl:text>
|
39
|
+
This message contains HTML content for a rich display.
|
40
|
+
|
41
|
+
Please enable the HTML view or use an HTML compatible email client.
|
42
|
+
</xsl:text>
|
43
|
+
</xsl:template>
|
44
|
+
|
45
|
+
<!-- This HTML version does not contain any images -->
|
46
|
+
<xsl:template name="images"/>
|
47
|
+
|
48
|
+
<xsl:template name="html">
|
49
|
+
<!-- The root element needs to be created with xsl:element to prevent namespaces sneaking in. -->
|
50
|
+
<xsl:element name="html">
|
51
|
+
<head>
|
52
|
+
<title>Ticket Summary for <xsl:value-of select="/clientsplugin/client/name"/></title>
|
53
|
+
<style type="text/css">
|
54
|
+
body {
|
55
|
+
background: #f3f3f3;
|
56
|
+
}
|
57
|
+
.ticket {
|
58
|
+
background: #eee;
|
59
|
+
padding: 0;
|
60
|
+
margin: 2px;
|
61
|
+
margin-bottom: 20px;
|
62
|
+
border: 1px solid #222;
|
63
|
+
}
|
64
|
+
.id {
|
65
|
+
float: left;
|
66
|
+
margin: 0;
|
67
|
+
padding: 5px;
|
68
|
+
text-align: center;
|
69
|
+
background: #222;
|
70
|
+
color: #eee;
|
71
|
+
width: 5em;
|
72
|
+
font-weight: bold;
|
73
|
+
}
|
74
|
+
.summary {
|
75
|
+
float: left;
|
76
|
+
margin: 0 0 0 1em;
|
77
|
+
padding: 5px;
|
78
|
+
font-style: italic;
|
79
|
+
}
|
80
|
+
.description {
|
81
|
+
clear: both;
|
82
|
+
margin: 2em;
|
83
|
+
margin-top: 3em;
|
84
|
+
padding: 1em;
|
85
|
+
border: 1px solid #222;
|
86
|
+
background: #fff;
|
87
|
+
}
|
88
|
+
.due {
|
89
|
+
clear: both;
|
90
|
+
float: right;
|
91
|
+
margin: 4px;
|
92
|
+
padding: 0;
|
93
|
+
font-variant: small-caps;
|
94
|
+
}
|
95
|
+
.due:before {
|
96
|
+
content: "Expected Delivery Date: ";
|
97
|
+
}
|
98
|
+
.fin {
|
99
|
+
clear: both;
|
100
|
+
}
|
101
|
+
</style>
|
102
|
+
</head>
|
103
|
+
<body>
|
104
|
+
<h1>Ticket Summary for <xsl:value-of select="/clientsplugin/client/name"/></h1>
|
105
|
+
<xsl:choose>
|
106
|
+
<xsl:when test="/clientsplugin/changes/ticket">
|
107
|
+
<xsl:for-each select="/clientsplugin/changes/ticket">
|
108
|
+
<div class="ticket">
|
109
|
+
<div class="id">#<xsl:value-of select="id"/></div>
|
110
|
+
<div class="summary"><xsl:value-of select="summary"/></div>
|
111
|
+
<div class="description">
|
112
|
+
<xsl:if test="description!=''">
|
113
|
+
<xsl:copy-of select="description"/>
|
114
|
+
</xsl:if>
|
115
|
+
<xsl:for-each select="changelog/detail">
|
116
|
+
<hr />
|
117
|
+
<xsl:copy-of select="."/>
|
118
|
+
</xsl:for-each>
|
119
|
+
</div>
|
120
|
+
<div class="due"><xsl:value-of select="due"/></div>
|
121
|
+
<div class="fin"></div>
|
122
|
+
</div>
|
123
|
+
</xsl:for-each>
|
124
|
+
</xsl:when>
|
125
|
+
<xsl:otherwise>
|
126
|
+
<p>You do not currently have any active tickets</p>
|
127
|
+
</xsl:otherwise>
|
128
|
+
</xsl:choose>
|
129
|
+
</body>
|
130
|
+
</xsl:element>
|
131
|
+
</xsl:template>
|
132
|
+
</xsl:stylesheet>
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
# run-client-event
|
4
|
+
# ----------------------------------------------------------------------------
|
5
|
+
# Copyright (c) 2008 Colin Guthrie
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
# of this software and associated documentation files (the "Software"), to
|
9
|
+
# deal in the Software without restriction, including without limitation the
|
10
|
+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
11
|
+
# sell copies of the Software, and to permit persons to whom the Software is
|
12
|
+
# furnished to do so, subject to the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be included in
|
15
|
+
# all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
20
|
+
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
22
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
23
|
+
# IN THE SOFTWARE.
|
24
|
+
# ----------------------------------------------------------------------------
|
25
|
+
|
26
|
+
# This email integration script is meant to interface to the Trac
|
27
|
+
# (http://www.edgewall.com/products/trac/) issue tracking/wiki/etc
|
28
|
+
# system
|
29
|
+
|
30
|
+
|
31
|
+
import os
|
32
|
+
import sys
|
33
|
+
import locale
|
34
|
+
import time
|
35
|
+
from optparse import OptionParser
|
36
|
+
from StringIO import StringIO
|
37
|
+
|
38
|
+
from trac import __version__
|
39
|
+
from trac.core import *
|
40
|
+
from trac.env import open_environment
|
41
|
+
from trac.util.datefmt import format_date, to_datetime
|
42
|
+
from trac.wiki import wiki_to_html
|
43
|
+
from genshi import escape
|
44
|
+
|
45
|
+
|
46
|
+
parser = OptionParser()
|
47
|
+
depr = '(not used anymore)'
|
48
|
+
parser.add_option('-e', '--env', dest='envpath',
|
49
|
+
help='Required. Path to the Trac environment.')
|
50
|
+
parser.add_option('-c', '--event', dest='event',
|
51
|
+
help='The client event to run (required)')
|
52
|
+
#parser.add_option('-d', action='store_true', dest='debug',
|
53
|
+
# help='Turn on debug mode - does not update database and prints verbose messages.')
|
54
|
+
#parser.add_option('-m', '--mail', dest='mail',
|
55
|
+
# help='Email override. Useful in combination with -d.')
|
56
|
+
#parser.set_defaults(period='daily', mailtype='summary')
|
57
|
+
(options, args) = parser.parse_args(sys.argv[1:])
|
58
|
+
|
59
|
+
|
60
|
+
class SendClientFakeReq:
|
61
|
+
def __init__(self):
|
62
|
+
class SendClientFakeHref:
|
63
|
+
def __call__(self, *args, **keywords):
|
64
|
+
return ''
|
65
|
+
def wiki(self, *args, **keywords):
|
66
|
+
return ''
|
67
|
+
def ticket(self, num):
|
68
|
+
return '#%d' % (num)
|
69
|
+
self.href = SendClientFakeHref()
|
70
|
+
self.abs_href = SendClientFakeHref()
|
71
|
+
self.perm = []
|
72
|
+
|
73
|
+
def __call__(self, *args, **keywords):
|
74
|
+
return ''
|
75
|
+
def perm(self, *args, **keywords):
|
76
|
+
return []
|
77
|
+
|
78
|
+
class RunClientEvents:
|
79
|
+
|
80
|
+
def __init__(self):
|
81
|
+
locale.setlocale(locale.LC_ALL, '')
|
82
|
+
self.env = open_environment(options.envpath)
|
83
|
+
self.req = SendClientFakeReq()
|
84
|
+
|
85
|
+
# Sync the repo so that any commits that happen to have been made
|
86
|
+
# that include client comments are included.
|
87
|
+
repos = self.env.get_repository()
|
88
|
+
repos.sync()
|
89
|
+
|
90
|
+
from clients.events import ClientEvent
|
91
|
+
ClientEvent.triggerall(self.env, self.req, options.event)
|
92
|
+
|
93
|
+
if __name__ == "__main__":
|
94
|
+
if not options.envpath or not options.event:
|
95
|
+
print "For usage: %s --help" % (sys.argv[0])
|
96
|
+
else:
|
97
|
+
RunClientEvents()
|
@@ -0,0 +1,161 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
|
3
|
+
<xsl:stylesheet
|
4
|
+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
5
|
+
version="1.0">
|
6
|
+
|
7
|
+
<xsl:output method="html" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
|
8
|
+
<xsl:decimal-format name="GBP" decimal-separator="." grouping-separator=","/>
|
9
|
+
|
10
|
+
<!-- Match the root of the XML render the three views -->
|
11
|
+
<xsl:template match="/">
|
12
|
+
<xsl:choose>
|
13
|
+
<xsl:when test="$view='html'">
|
14
|
+
<!-- Should return HTML as you see fit -->
|
15
|
+
<xsl:call-template name="html"/>
|
16
|
+
</xsl:when>
|
17
|
+
<xsl:when test="$view='images'">
|
18
|
+
<!--
|
19
|
+
Should return a list of images to embed in the following format:
|
20
|
+
|
21
|
+
<images>
|
22
|
+
<img id="myimage" src="/local/path/to/image"/>
|
23
|
+
</images>
|
24
|
+
|
25
|
+
Where "myimage" is references in your HTML image as <img src="cid:myimage" />
|
26
|
+
-->
|
27
|
+
<xsl:call-template name="images"/>
|
28
|
+
</xsl:when>
|
29
|
+
<xsl:otherwise>
|
30
|
+
<!-- The plain text portion of the email -->
|
31
|
+
<xsl:call-template name="plain"/>
|
32
|
+
</xsl:otherwise>
|
33
|
+
</xsl:choose>
|
34
|
+
</xsl:template>
|
35
|
+
|
36
|
+
<!-- Simple (cop-out) implementation of a plain text message -->
|
37
|
+
<xsl:template name="plain">
|
38
|
+
<xsl:text>
|
39
|
+
This message contains HTML content for a rich display.
|
40
|
+
|
41
|
+
Please enable the HTML view or use an HTML compatible email client.
|
42
|
+
</xsl:text>
|
43
|
+
</xsl:template>
|
44
|
+
|
45
|
+
<!-- This HTML version does not contain any images -->
|
46
|
+
<xsl:template name="images"/>
|
47
|
+
|
48
|
+
<xsl:template name="html">
|
49
|
+
<!-- The root element needs to be created with xsl:element to prevent namespaces sneaking in. -->
|
50
|
+
<xsl:element name="html">
|
51
|
+
<head>
|
52
|
+
<title>Ticket Summary for <xsl:value-of select="/clientsplugin/client/name"/></title>
|
53
|
+
<style type="text/css">
|
54
|
+
body {
|
55
|
+
background: #f3f3f3;
|
56
|
+
}
|
57
|
+
fieldset.milestone {
|
58
|
+
margin-top: 3em;
|
59
|
+
}
|
60
|
+
fieldset.ticket {
|
61
|
+
margin-top: 2em;
|
62
|
+
background: #eee;
|
63
|
+
}
|
64
|
+
.description {
|
65
|
+
margin: 0.5em;
|
66
|
+
padding: 0.5em;
|
67
|
+
border: 1px solid #222;
|
68
|
+
background: #fff;
|
69
|
+
}
|
70
|
+
.status {
|
71
|
+
margin: 4px;
|
72
|
+
padding: 0;
|
73
|
+
font-variant: small-caps;
|
74
|
+
}
|
75
|
+
dl.milestone dt {
|
76
|
+
float: left;
|
77
|
+
margin-right: 0.5em;
|
78
|
+
font-style: italic;
|
79
|
+
}
|
80
|
+
dl.milestone dt:after {
|
81
|
+
content: ':';
|
82
|
+
}
|
83
|
+
</style>
|
84
|
+
</head>
|
85
|
+
<body>
|
86
|
+
<h1>Ticket Summary for <xsl:value-of select="/clientsplugin/client/name"/></h1>
|
87
|
+
<xsl:choose>
|
88
|
+
<xsl:when test="/clientsplugin/summary/ticket">
|
89
|
+
<xsl:for-each select="/clientsplugin/milestones/milestone">
|
90
|
+
<xsl:sort select="duetimestamp" order="asscending"/>
|
91
|
+
<xsl:variable name="ms" select="./name" />
|
92
|
+
<xsl:if test="/clientsplugin/summary/ticket[milestone=$ms]">
|
93
|
+
<fieldset class="milestone">
|
94
|
+
<legend class="milestone">
|
95
|
+
<xsl:text>Milestone: </xsl:text>
|
96
|
+
<xsl:value-of select="$ms" />
|
97
|
+
</legend>
|
98
|
+
<xsl:if test="./description!=''">
|
99
|
+
<div class="milestone description">
|
100
|
+
<xsl:value-of select="./description" />
|
101
|
+
</div>
|
102
|
+
</xsl:if>
|
103
|
+
<xsl:if test="./due">
|
104
|
+
<dl class="milestone">
|
105
|
+
<dt>Estimated delivery date</dt>
|
106
|
+
<dd><xsl:value-of select="./due" /></dd>
|
107
|
+
<xsl:if test="./completed">
|
108
|
+
<dt>Completed on</dt>
|
109
|
+
<dd><xsl:value-of select="./completed" /></dd>
|
110
|
+
</xsl:if>
|
111
|
+
<xsl:if test="./estimatedhours">
|
112
|
+
<dt>Total estimated development time</dt>
|
113
|
+
<dd><xsl:value-of select="./estimatedhours" /></dd>
|
114
|
+
</xsl:if>
|
115
|
+
</dl>
|
116
|
+
</xsl:if>
|
117
|
+
<xsl:for-each select="/clientsplugin/summary/ticket[milestone=$ms]">
|
118
|
+
<xsl:call-template name="print-ticket" />
|
119
|
+
</xsl:for-each>
|
120
|
+
</fieldset>
|
121
|
+
</xsl:if>
|
122
|
+
</xsl:for-each>
|
123
|
+
<xsl:variable name="ms" select="''" />
|
124
|
+
<xsl:if test="/clientsplugin/summary/ticket[milestone=$ms]">
|
125
|
+
<fieldset class="milestone">
|
126
|
+
<legend class="milestone">
|
127
|
+
Tickets not allocated to specific milestones
|
128
|
+
</legend>
|
129
|
+
<div class="milestone description">
|
130
|
+
<p>The following tickets are not allocated to any specific milestone.</p>
|
131
|
+
</div>
|
132
|
+
<xsl:for-each select="/clientsplugin/summary/ticket[milestone=$ms]">
|
133
|
+
<xsl:call-template name="print-ticket" />
|
134
|
+
</xsl:for-each>
|
135
|
+
</fieldset>
|
136
|
+
</xsl:if>
|
137
|
+
</xsl:when>
|
138
|
+
<xsl:otherwise>
|
139
|
+
<p>You do not currently have any active tickets</p>
|
140
|
+
</xsl:otherwise>
|
141
|
+
</xsl:choose>
|
142
|
+
</body>
|
143
|
+
</xsl:element>
|
144
|
+
</xsl:template>
|
145
|
+
|
146
|
+
<xsl:template name="print-ticket">
|
147
|
+
<fieldset class="ticket">
|
148
|
+
<legend class="ticket">
|
149
|
+
Ticket #<xsl:value-of select="id"/>: <xsl:value-of select="summary"/>
|
150
|
+
</legend>
|
151
|
+
<xsl:if test="description!=''">
|
152
|
+
<div class="ticket description"><xsl:copy-of select="description"/></div>
|
153
|
+
</xsl:if>
|
154
|
+
<div class="status">Status: <xsl:value-of select="status"/></div>
|
155
|
+
<xsl:if test="estimatedhours">
|
156
|
+
<div class="estimate">Estimated development time: <xsl:value-of select="estimatedhours"/></div>
|
157
|
+
</xsl:if>
|
158
|
+
<!-- <div class="due"><xsl:value-of select="due"/></div> -->
|
159
|
+
</fieldset>
|
160
|
+
</xsl:template>
|
161
|
+
</xsl:stylesheet>
|