keithsalisbury-subtrac 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/VERSION.yml +1 -1
  2. data/bin/subtrac +2 -0
  3. data/lib/subtrac.rb +85 -50
  4. data/lib/subtrac/config/config.yml +22 -19
  5. data/lib/subtrac/templates/location.erb +2 -2
  6. data/lib/subtrac/templates/projects/blank/trac/wiki/WikiStart +1 -1
  7. data/lib/subtrac/templates/trac.erb +1 -1
  8. data/lib/subtrac/templates/vhost.erb +6 -6
  9. metadata +1 -105
  10. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/advancedworkflow/__init__.py +0 -0
  11. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/advancedworkflow/controller.py +0 -419
  12. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/setup.cfg +0 -3
  13. data/lib/subtrac/trac-plugins/advancedticketworkflowplugin/setup.py +0 -20
  14. data/lib/subtrac/trac-plugins/clientsplugin/clients/__init__.py +0 -0
  15. data/lib/subtrac/trac-plugins/clientsplugin/clients/action.py +0 -28
  16. data/lib/subtrac/trac-plugins/clientsplugin/clients/action_email.py +0 -168
  17. data/lib/subtrac/trac-plugins/clientsplugin/clients/action_zendesk_forum.py +0 -137
  18. data/lib/subtrac/trac-plugins/clientsplugin/clients/admin.py +0 -91
  19. data/lib/subtrac/trac-plugins/clientsplugin/clients/api.py +0 -199
  20. data/lib/subtrac/trac-plugins/clientsplugin/clients/client.py +0 -105
  21. data/lib/subtrac/trac-plugins/clientsplugin/clients/events.py +0 -287
  22. data/lib/subtrac/trac-plugins/clientsplugin/clients/eventsadmin.py +0 -71
  23. data/lib/subtrac/trac-plugins/clientsplugin/clients/htdocs/clients.css +0 -4
  24. data/lib/subtrac/trac-plugins/clientsplugin/clients/model.py +0 -135
  25. data/lib/subtrac/trac-plugins/clientsplugin/clients/processor.py +0 -70
  26. data/lib/subtrac/trac-plugins/clientsplugin/clients/reportmanager.py +0 -142
  27. data/lib/subtrac/trac-plugins/clientsplugin/clients/reports.py +0 -231
  28. data/lib/subtrac/trac-plugins/clientsplugin/clients/summary.py +0 -27
  29. data/lib/subtrac/trac-plugins/clientsplugin/clients/summary_milestone.py +0 -152
  30. data/lib/subtrac/trac-plugins/clientsplugin/clients/summary_ticketchanges.py +0 -160
  31. data/lib/subtrac/trac-plugins/clientsplugin/clients/templates/admin_client_events.html +0 -124
  32. data/lib/subtrac/trac-plugins/clientsplugin/clients/templates/admin_clients.html +0 -134
  33. data/lib/subtrac/trac-plugins/clientsplugin/cron/changes.xslt +0 -132
  34. data/lib/subtrac/trac-plugins/clientsplugin/cron/run-client-event +0 -97
  35. data/lib/subtrac/trac-plugins/clientsplugin/cron/summary.xslt +0 -161
  36. data/lib/subtrac/trac-plugins/clientsplugin/setup.py +0 -43
  37. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/__init__.py +0 -4
  38. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/burndownchart.py +0 -273
  39. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/hoursinplaceeditor.py +0 -44
  40. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/hoursremaining.py +0 -36
  41. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery-1.2.3.min.js +0 -32
  42. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery.jeditable.js +0 -409
  43. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/htdocs/jquery.jeditable.mini.js +0 -30
  44. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/templates/edithours.html +0 -53
  45. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/burndownchart.py +0 -181
  46. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/hoursremaining.py +0 -66
  47. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/tests/workloadchart.py +0 -47
  48. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/utils.py +0 -93
  49. data/lib/subtrac/trac-plugins/estimationtoolsplugin/estimationtools/workloadchart.py +0 -86
  50. data/lib/subtrac/trac-plugins/estimationtoolsplugin/setup.py +0 -20
  51. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/SumRollups.js +0 -23
  52. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/adw_tracdb.py +0 -128
  53. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/git-post-receive +0 -40
  54. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/trac-post-commit.py +0 -285
  55. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/trac_billing.py +0 -173
  56. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/utils/__init__.py +0 -0
  57. data/lib/subtrac/trac-plugins/timingandestimationplugin/scripts/utils/mail.py +0 -164
  58. data/lib/subtrac/trac-plugins/timingandestimationplugin/setup.py +0 -69
  59. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/__init__.py +0 -1
  60. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/api.py +0 -292
  61. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/blackmagic.py +0 -172
  62. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/dbhelper.py +0 -178
  63. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/billingplugin.css +0 -25
  64. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/field_disabler.js +0 -6
  65. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/formatDate.js +0 -356
  66. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/tip_centerwindow.js +0 -100
  67. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/tip_followscroll.js +0 -84
  68. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/js/wz_tooltip.js +0 -1149
  69. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/linkifyer.js +0 -119
  70. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/query.js +0 -73
  71. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/htdocs/ticket.js +0 -165
  72. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/query_webui.py +0 -28
  73. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reportmanager.py +0 -221
  74. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reports.py +0 -675
  75. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/reports_filter.py +0 -150
  76. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/statuses.py +0 -25
  77. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/tande_filters.py +0 -131
  78. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/templates/billing.cs +0 -84
  79. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/templates/billing.html +0 -104
  80. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_daemon.py +0 -194
  81. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_policy.py +0 -62
  82. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/ticket_webui.py +0 -28
  83. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/usermanual.py +0 -127
  84. data/lib/subtrac/trac-plugins/timingandestimationplugin/timingandestimationplugin/webui.py +0 -129
  85. data/lib/subtrac/trac-plugins/worklogplugin/setup.py +0 -29
  86. data/lib/subtrac/trac-plugins/worklogplugin/worklog/__init__.py +0 -1
  87. data/lib/subtrac/trac-plugins/worklogplugin/worklog/api.py +0 -187
  88. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jqModal.css +0 -40
  89. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jqModal.js +0 -67
  90. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jquery.mousewheel.pack.js +0 -12
  91. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/jquery.timeentry.pack.js +0 -7
  92. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/tracWorklog.js +0 -40
  93. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/ui.datepicker.css +0 -208
  94. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/ui.datepicker.js +0 -1439
  95. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/work.png +0 -0
  96. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/work.xcf +0 -0
  97. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/worklogplugin.css +0 -80
  98. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/workstart.png +0 -0
  99. data/lib/subtrac/trac-plugins/worklogplugin/worklog/htdocs/workstop.png +0 -0
  100. data/lib/subtrac/trac-plugins/worklogplugin/worklog/manager.py +0 -336
  101. data/lib/subtrac/trac-plugins/worklogplugin/worklog/reports.py +0 -598
  102. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog.html +0 -45
  103. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_stop.html +0 -70
  104. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_user.html +0 -40
  105. data/lib/subtrac/trac-plugins/worklogplugin/worklog/templates/worklog_webadminui.html +0 -59
  106. data/lib/subtrac/trac-plugins/worklogplugin/worklog/ticket_daemon.py +0 -33
  107. data/lib/subtrac/trac-plugins/worklogplugin/worklog/ticket_filter.py +0 -153
  108. data/lib/subtrac/trac-plugins/worklogplugin/worklog/timeline_hook.py +0 -96
  109. data/lib/subtrac/trac-plugins/worklogplugin/worklog/usermanual.py +0 -29
  110. data/lib/subtrac/trac-plugins/worklogplugin/worklog/util.py +0 -31
  111. data/lib/subtrac/trac-plugins/worklogplugin/worklog/webadminui.py +0 -47
  112. data/lib/subtrac/trac-plugins/worklogplugin/worklog/webui.py +0 -174
  113. data/lib/subtrac/trac-plugins/worklogplugin/worklog/xmlrpc.py +0 -73
@@ -1,168 +0,0 @@
1
- import re
2
- import os
3
- import sys
4
- import locale
5
- import time
6
- import codecs
7
- from datetime import datetime
8
- from StringIO import StringIO
9
-
10
- from trac import __version__
11
- from trac.core import *
12
- from trac.env import open_environment
13
- from trac.util.datefmt import format_date, to_datetime
14
- from trac.wiki import wiki_to_html
15
- from genshi import escape
16
-
17
- from lxml import etree
18
- from clients.action import IClientActionProvider
19
-
20
-
21
- class ClientActionEmail(Component):
22
- implements(IClientActionProvider)
23
-
24
- client = None
25
- debug = False
26
-
27
- def get_name(self):
28
- return "Send Email"
29
-
30
- def get_description(self):
31
- return "Send an email to a certain list of addresses"
32
-
33
- def options(self, client=None):
34
- if client is None:
35
- yield {'name': 'XSLT', 'description': 'Formatting XSLT to convert the summary to an email', 'type': 'large'}
36
- yield {'name': 'Subject', 'description': 'Email subject (use %s to replace the active client name)', 'type': 'medium'}
37
- else:
38
- yield {'name': 'Email Addresses', 'description': 'Comma separated list of email addresses', 'type': 'medium'}
39
-
40
-
41
- def init(self, event, client):
42
- self.client = client
43
- if not event.action_options.has_key('XSLT') or not event.action_options['XSLT']['value']:
44
- return False
45
- try:
46
- self.transform = etree.XSLT(etree.fromstring(str(event.action_options['XSLT']['value'])))
47
- except:
48
- self.env.log.error("Error: Cannot load/parse stylesheet")
49
- return False
50
-
51
- if not event.action_client_options.has_key('Email Addresses') or not event.action_client_options['Email Addresses']['value']:
52
- return False
53
-
54
- self.emails = []
55
- for email in event.action_client_options['Email Addresses']['value'].replace(',', ' ').split(' '):
56
- if '' != email.strip():
57
- self.emails.append(email.strip())
58
-
59
- if not self.emails:
60
- return False
61
-
62
- if not event.action_options.has_key('Subject') or not event.action_options['Subject']['value']:
63
- self.subject = 'Ticket Summary for %s'
64
- else:
65
- self.subject = event.action_options['Subject']['value']
66
-
67
- if self.subject.find('%s') >= 0:
68
- self.subject = self.subject % (client,)
69
-
70
- return True
71
-
72
-
73
- def perform(self, req, summary):
74
- if summary is None:
75
- return False
76
- self.config = self.env.config
77
- self.encoding = 'utf-8'
78
- subject = self.subject
79
-
80
- if not self.config.getbool('notification', 'smtp_enabled'):
81
- return False
82
- smtp_server = self.config['notification'].get('smtp_server')
83
- smtp_port = self.config['notification'].getint('smtp_port')
84
- from_email = self.config['notification'].get('smtp_from')
85
- from_name = self.config['notification'].get('smtp_from_name')
86
- replyto_email = self.config['notification'].get('smtp_replyto')
87
- from_email = from_email or replyto_email
88
- if not from_email:
89
- return False
90
-
91
- # Authentication info (optional)
92
- user_name = self.config['notification'].get('smtp_user')
93
- password = self.config['notification'].get('smtp_password')
94
-
95
- # Thanks to the author of this recipe:
96
- # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/473810
97
-
98
- from email.MIMEMultipart import MIMEMultipart
99
- from email.MIMEText import MIMEText
100
- from email.MIMEImage import MIMEImage
101
- from email.Charset import add_charset, SHORTEST
102
- add_charset( 'utf-8', SHORTEST, None, None )
103
-
104
- projname = self.config.get('project', 'name')
105
-
106
- # Create the root message and fill in the from, to, and subject headers
107
- msg_root = MIMEMultipart('alternative')
108
- msg_root['To'] = str(', ').join(self.emails)
109
-
110
- msg_root['X-Mailer'] = 'ClientsPlugin for Trac'
111
- msg_root['X-Trac-Version'] = __version__
112
- msg_root['X-Trac-Project'] = projname
113
- msg_root['Precedence'] = 'bulk'
114
- msg_root['Auto-Submitted'] = 'auto-generated'
115
- msg_root['Subject'] = subject
116
- msg_root['From'] = '%s <%s>' % (from_name or projname, from_email)
117
- msg_root['Reply-To'] = replyto_email
118
- msg_root.preamble = 'This is a multi-part message in MIME format.'
119
-
120
- view = 'plain'
121
- arg = "'%s'" % view
122
- result = self.transform(summary, view=arg)
123
- msg_text = MIMEText(str(result), view, self.encoding)
124
- msg_root.attach(msg_text)
125
-
126
- msg_related = MIMEMultipart('related')
127
- msg_root.attach(msg_related)
128
-
129
- view = 'html'
130
- arg = "'%s'" % view
131
- result = self.transform(summary, view=arg)
132
- #file = open('/tmp/send-client-email.html', 'w')
133
- #file.write(str(result))
134
- #file.close()
135
-
136
- msg_text = MIMEText(str(result), view, self.encoding)
137
- msg_related.attach(msg_text)
138
-
139
- # Handle image embedding...
140
- view = 'images'
141
- arg = "'%s'" % view
142
- result = self.transform(summary, view=arg)
143
- if result:
144
- images = result.getroot()
145
- if images:
146
- for img in images:
147
- if 'img' != img.tag:
148
- continue
149
- if not img.get('id') or not img.get('src'):
150
- continue
151
-
152
- fp = open(img.get('src'), 'rb')
153
- if not fp:
154
- continue
155
- msg_img = MIMEImage(fp.read())
156
- fp.close()
157
- msg_img.add_header('Content-ID', '<%s>' % img.get('id'))
158
- msg_related.attach(msg_img)
159
-
160
- # Send the email
161
- import smtplib
162
- smtp = smtplib.SMTP() #smtp_server, smtp_port)
163
- if False and user_name:
164
- smtp.login(user_name, password)
165
- smtp.connect()
166
- smtp.sendmail(from_email, self.emails, msg_root.as_string())
167
- smtp.quit()
168
- return True
@@ -1,137 +0,0 @@
1
- import re
2
- import os
3
- import sys
4
- import locale
5
- import time
6
- import codecs
7
- import httplib
8
- import urlparse
9
- from datetime import datetime
10
- from StringIO import StringIO
11
-
12
- from trac.core import *
13
- from trac.env import open_environment
14
- from trac.util.datefmt import format_date, to_datetime
15
- from trac.wiki import wiki_to_html
16
- from genshi import escape
17
-
18
- from lxml import etree
19
- from clients.action import IClientActionProvider
20
-
21
-
22
- class ClientActionZendesk(Component):
23
- implements(IClientActionProvider)
24
-
25
- client = None
26
- debug = False
27
-
28
- def get_name(self):
29
- return "Post to Zendesk"
30
-
31
- def get_description(self):
32
- return "Post the summary to a Zendesk forum topic"
33
-
34
- def options(self, client=None):
35
- if client is None:
36
- yield {'name': 'XSLT', 'description': 'Formatting XSLT to convert the summary to a Zendesk compatible post', 'type': 'large'}
37
- yield {'name': 'Username', 'description': 'Zendesk username', 'type': 'medium'}
38
- yield {'name': 'Password', 'description': 'Zendesk password', 'type': 'medium'}
39
- yield {'name': 'Method', 'description': 'Interaction Method', 'type': 'list', 'vals': ['POST', 'PUT']}
40
- else:
41
- yield {'name': 'Zendesk URI', 'description': 'Zendesk Forum REST URI', 'type': 'medium'}
42
-
43
-
44
- def init(self, event, client):
45
- self.client = client
46
- if not event.action_options.has_key('XSLT') or not event.action_options['XSLT']['value']:
47
- return False
48
- try:
49
- self.transform = etree.XSLT(etree.fromstring(str(event.action_options['XSLT']['value'])))
50
- except:
51
- print "Error: Cannot load/parse stylesheet"
52
- return False
53
-
54
- if not event.action_options.has_key('Username') or not event.action_options['Username']['value']:
55
- return False
56
- self.username = event.action_options['Username']['value']
57
-
58
- if not event.action_options.has_key('Password') or not event.action_options['Password']['value']:
59
- return False
60
- self.password = event.action_options['Password']['value']
61
-
62
- if not event.action_options.has_key('Method') or not event.action_options['Method']['value']:
63
- return False
64
- self.method = event.action_options['Method']['value']
65
-
66
- if not event.action_client_options.has_key('Zendesk URI') or not event.action_client_options['Zendesk URI']['value']:
67
- return False
68
- self.uri = event.action_client_options['Zendesk URI']['value']
69
-
70
- return True
71
-
72
-
73
- def perform(self, req, summary):
74
- def parseuri(uri):
75
- """Parse URI, return (host, port, path) tuple.
76
-
77
- >>> parseuri('http://example.org/testing?somequery#frag')
78
- ('example.org', 80, '/testing?somequery')
79
- >>> parseuri('http://example.net:8080/test.html')
80
- ('example.net', 8080, '/test.html')
81
- """
82
-
83
- scheme, netplace, path, query, fragid = urlparse.urlsplit(uri)
84
-
85
- if ':' in netplace:
86
- host, port = netplace.split(':', 2)
87
- port = int(port)
88
- else: host, port = netplace, 80
89
-
90
- if query: path += '?' + query
91
-
92
- return host, port, path
93
-
94
-
95
-
96
- if summary is None:
97
- return False
98
-
99
- result = self.transform(summary)
100
-
101
- username = self.username
102
- password = self.password
103
- uri = self.uri
104
-
105
- host, port, path = parseuri(uri)
106
-
107
- okay = set([200, 201, 204])
108
-
109
- import base64
110
- userpass = username + ':' + password
111
- userpass = base64.encodestring(userpass).strip()
112
- authorization = 'Basic ' + userpass
113
-
114
- # Attempt to HTTP PUT the data
115
- h = httplib.HTTPConnection(host, port)
116
-
117
- data = str(result)
118
- h.putrequest('PUT', path)
119
-
120
- h.putheader('User-Agent', 'Trac/1.0')
121
- h.putheader('Accept', 'application/xml')
122
- h.putheader('Content-Type', 'text/xml')
123
- h.putheader('Authorization', authorization)
124
- h.putheader('Content-Length', len(data))
125
- h.endheaders()
126
-
127
- h.send(str(data))
128
-
129
- resp = h.getresponse()
130
- status = resp.status # an int
131
-
132
- # Got a response, now decide how to act upon it
133
- if status not in okay:
134
- print 'Got "%s %s"' % (status, resp.reason)
135
- return False
136
-
137
- return True
@@ -1,91 +0,0 @@
1
- from trac.core import *
2
- from trac.perm import PermissionSystem
3
- #from trac.ticket.model import AbstractEnum
4
- #from trac.ticket.admin import AbstractEnumAdminPage
5
- from trac.ticket.admin import TicketAdminPanel
6
-
7
-
8
- from clients.model import Client
9
- from clients.events import ClientEvent
10
- from trac.util.datefmt import utc, parse_date, get_date_format_hint, \
11
- get_datetime_format_hint
12
- from trac.web.chrome import add_link, add_script
13
-
14
- class ClientAdminPanel(TicketAdminPanel):
15
-
16
- _type = 'clients'
17
- _label = ('Client', 'Clients')
18
-
19
- # TicketAdminPanel methods
20
- def _render_admin_panel(self, req, cat, page, client):
21
- # Detail view?
22
- if client:
23
- clnt = Client(self.env, client)
24
- events = ClientEvent.select(self.env, client)
25
- if req.method == 'POST':
26
- if req.args.get('save'):
27
- clnt.name = req.args.get('name')
28
- clnt.description = req.args.get('description')
29
- clnt.changes_list = req.args.get('changes_list')
30
- clnt.changes_period = req.args.get('changes_period')
31
- clnt.summary_list = req.args.get('summary_list')
32
- clnt.summary_period = req.args.get('summary_period')
33
- clnt.default_rate = req.args.get('default_rate')
34
- clnt.currency = req.args.get('currency')
35
- clnt.update()
36
-
37
- db = self.env.get_db_cnx()
38
- for clev in events:
39
- for option in clev.summary_client_options:
40
- arg = 'summary-option-%s-%s' % (clev.md5, clev.summary_client_options[option]['md5'])
41
- clev.summary_client_options[option]['value'] = req.args.get(arg)
42
- for option in clev.action_client_options:
43
- arg = 'action-option-%s-%s' % (clev.md5, clev.action_client_options[option]['md5'])
44
- clev.action_client_options[option]['value'] = req.args.get(arg)
45
- clev.update_options(client, db)
46
- db.commit()
47
-
48
- req.redirect(req.href.admin(cat, page))
49
- elif req.args.get('cancel'):
50
- req.redirect(req.href.admin(cat, page))
51
-
52
- add_script(req, 'common/js/wikitoolbar.js')
53
- data = {'view': 'detail', 'client': clnt, 'events': events}
54
-
55
- else:
56
- if req.method == 'POST':
57
- # Add Client
58
- if req.args.get('add') and req.args.get('name'):
59
- clnt = Client(self.env)
60
- clnt.name = req.args.get('name')
61
- clnt.insert()
62
- req.redirect(req.href.admin(cat, page))
63
-
64
- # Remove clients
65
- elif req.args.get('remove') and req.args.get('sel'):
66
- sel = req.args.get('sel')
67
- sel = isinstance(sel, list) and sel or [sel]
68
- if not sel:
69
- raise TracError('No client selected')
70
- db = self.env.get_db_cnx()
71
- for name in sel:
72
- clnt = Client(self.env, name, db=db)
73
- clnt.delete(db=db)
74
- db.commit()
75
- req.redirect(req.href.admin(cat, page))
76
-
77
- # Set default client
78
- elif req.args.get('apply'):
79
- if req.args.get('default'):
80
- name = req.args.get('default')
81
- self.log.info('Setting default client to %s', name)
82
- self.config.set('ticket', 'default_client', name)
83
- self.config.save()
84
- req.redirect(req.href.admin(cat, page))
85
-
86
- default = self.config.get('ticket', 'default_client')
87
- data = {'view': 'list',
88
- 'clients': Client.select(self.env),
89
- 'default': default}
90
-
91
- return 'admin_clients.html', data
@@ -1,199 +0,0 @@
1
- import time
2
- from trac.core import *
3
- from trac.env import IEnvironmentSetupParticipant
4
- from reportmanager import CustomReportManager
5
-
6
- class ClientsSetupParticipant(Component):
7
- implements(IEnvironmentSetupParticipant)
8
-
9
- db_version_key = None
10
- db_version = None
11
- db_installed_version = None
12
-
13
- def __init__(self):
14
- self.db_version_key = 'clients_plugin_version'
15
- self.db_version = 5
16
- self.db_installed_version = None
17
-
18
- # Initialise database schema version tracking.
19
- db = self.env.get_db_cnx()
20
- cursor = db.cursor()
21
- cursor.execute("SELECT value FROM system WHERE name=%s", (self.db_version_key,))
22
- try:
23
- self.db_installed_version = int(cursor.fetchone()[0])
24
- except:
25
- self.db_installed_version = 0
26
- cursor.execute("INSERT INTO system (name,value) VALUES(%s,%s)",
27
- (self.db_version_key, self.db_installed_version))
28
- db.commit()
29
- db.close()
30
-
31
- def system_needs_upgrade(self):
32
- return self.db_installed_version < self.db_version
33
-
34
- def do_db_upgrade(self):
35
- db = self.env.get_db_cnx()
36
- cursor = db.cursor()
37
-
38
- # Do the staged updates
39
- try:
40
- if self.db_installed_version < 2:
41
- print 'Creating client table'
42
- cursor.execute('CREATE TABLE client ('
43
- 'name TEXT,'
44
- 'description TEXT,'
45
- 'changes_list TEXT,'
46
- 'changes_period TEXT,'
47
- 'changes_lastupdate INTEGER,'
48
- 'summary_list TEXT,'
49
- 'summary_period TEXT,'
50
- 'summary_lastupdate INTEGER'
51
- ')')
52
- # Import old Enums
53
- cursor.execute('INSERT INTO client (name) '
54
- 'SELECT name FROM enum WHERE type=%s', ('client',))
55
- # Clean them out
56
- cursor.execute('DELETE FROM enum WHERE type=%s', ('client',))
57
-
58
- if self.db_installed_version < 3:
59
- print 'Updating clients table (v3)'
60
- cursor.execute('ALTER TABLE client '
61
- 'ADD COLUMN default_rate INTEGER')
62
- cursor.execute('ALTER TABLE client '
63
- 'ADD COLUMN currency TEXT')
64
-
65
- if self.db_installed_version < 4:
66
- print 'Updating clients table (v4)'
67
- cursor.execute('CREATE TABLE client_events ('
68
- 'name TEXT,'
69
- 'summary TEXT,'
70
- 'action TEXT,'
71
- 'lastrun INTEGER'
72
- ')')
73
- cursor.execute('CREATE TABLE client_event_summary_options ('
74
- 'client_event TEXT,'
75
- 'client TEXT,'
76
- 'name TEXT,'
77
- 'value TEXT'
78
- ')')
79
- cursor.execute('CREATE TABLE client_event_action_options ('
80
- 'client_event TEXT,'
81
- 'client TEXT,'
82
- 'name TEXT,'
83
- 'value TEXT'
84
- ')')
85
-
86
- if self.db_installed_version < 5:
87
- print 'Updating clients table (v5)'
88
- cursor.execute('INSERT INTO client_events '
89
- 'SELECT "Weekly Summary", "Milestone Summary", "Send Email", MAX(summary_lastupdate) '
90
- 'FROM client')
91
- cursor.execute('INSERT INTO client_event_action_options '
92
- 'SELECT "Weekly Summary", name, "Email Addresses", summary_list '
93
- 'FROM client '
94
- 'WHERE summary_list!=""')
95
- cursor.execute('INSERT INTO client_events '
96
- 'SELECT "Ticket Changes", "Ticket Change Summary", "Send Email", MAX(changes_lastupdate) '
97
- 'FROM client')
98
- cursor.execute('INSERT INTO client_event_action_options '
99
- 'SELECT "Ticket Changes", name, "Email Addresses", changes_list '
100
- 'FROM client '
101
- 'WHERE changes_list!=""')
102
- cursor.execute('CREATE TEMPORARY TABLE client_tmp ('
103
- 'name TEXT,'
104
- 'description TEXT,'
105
- 'default_rate INTEGER,'
106
- 'currency TEXT'
107
- ')')
108
- cursor.execute('INSERT INTO client_tmp SELECT name, description, default_rate, currency FROM client')
109
- cursor.execute('DROP TABLE client')
110
- cursor.execute('CREATE TABLE client ('
111
- 'name TEXT,'
112
- 'description TEXT,'
113
- 'default_rate INTEGER,'
114
- 'currency TEXT'
115
- ')')
116
- cursor.execute('INSERT INTO client SELECT name, description, default_rate, currency FROM client_tmp')
117
- cursor.execute('DROP TABLE client_tmp')
118
-
119
- #if self.db_installed_version < 6:
120
- # print 'Updating clients table (v6)'
121
- # cursor.execute('...')
122
-
123
- # Updates complete, set the version
124
- cursor.execute("UPDATE system SET value=%s WHERE name=%s",
125
- (self.db_version, self.db_version_key))
126
- db.commit()
127
- db.close()
128
- except Exception, e:
129
- self.log.error("WorklogPlugin Exception: %s" % (e,));
130
- db.rollback()
131
-
132
- def do_reports_upgrade(self):
133
- mgr = CustomReportManager(self.env, self.log)
134
- r = __import__('reports', globals(), locals(), ['reports'])
135
-
136
- for report_group in r.reports:
137
- rlist = report_group['reports']
138
- group_title = report_group['title']
139
- for report in rlist:
140
- title = report['title']
141
- new_version = report['version']
142
- mgr.add_report(report["title"], 'Clients Plugin', \
143
- report['description'], report['sql'], \
144
- report['uuid'], report['version'],
145
- 'Timing and Estimation Plugin',
146
- group_title)
147
-
148
- def ticket_fields_need_upgrade(self):
149
- section = 'ticket-custom'
150
- return ('text' != self.config.get(section, 'client') \
151
- or 'text' != self.config.get(section, 'clientrate'))
152
-
153
- def do_ticket_field_upgrade(self):
154
- section = 'ticket-custom'
155
-
156
- self.config.set(section,'client', 'text')
157
- self.config.set(section,'client.label', 'Client')
158
-
159
- self.config.set(section,'clientrate', 'text')
160
- self.config.set(section,'clientrate.label', 'Client Charge Rate')
161
-
162
- self.config.save();
163
-
164
-
165
- # IEnvironmentSetupParticipant methods
166
- def environment_created(self):
167
- """Called when a new Trac environment is created."""
168
- if self.environment_needs_upgrade(None):
169
- self.upgrade_environment(None)
170
-
171
- def environment_needs_upgrade(self, db):
172
- """Called when Trac checks whether the environment needs to be upgraded.
173
-
174
- Should return `True` if this participant needs an upgrade to be
175
- performed, `False` otherwise.
176
-
177
- """
178
- return (self.system_needs_upgrade() \
179
- or self.ticket_fields_need_upgrade())
180
-
181
- def upgrade_environment(self, db):
182
- """Actually perform an environment upgrade.
183
-
184
- Implementations of this method should not commit any database
185
- transactions. This is done implicitly after all participants have
186
- performed the upgrades they need without an error being raised.
187
- """
188
- print 'ClientsPlugin needs an upgrade'
189
- print ' * Upgrading db'
190
- self.do_db_upgrade()
191
- print ' * Upgrading reports'
192
- self.do_reports_upgrade()
193
-
194
- if self.ticket_fields_need_upgrade():
195
- print ' * Upgrading fields'
196
- self.do_ticket_field_upgrade()
197
-
198
- print 'Done Upgrading'
199
-