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,419 +0,0 @@
1
- """Trac plugin that provides a number of advanced operations for customizable
2
- workflows.
3
- """
4
-
5
- import os
6
- import time
7
- from subprocess import call
8
- from genshi.builder import tag
9
-
10
- from trac.core import implements, Component
11
- from trac.ticket import model
12
- from trac.ticket.api import ITicketActionController
13
- from trac.ticket.default_workflow import ConfigurableTicketWorkflow
14
-
15
-
16
- class TicketWorkflowOpBase(Component):
17
- """Abstract base class for 'simple' ticket workflow operations."""
18
-
19
- implements(ITicketActionController)
20
- abstract = True
21
-
22
- _op_name = None # Must be specified.
23
-
24
- # ITicketActionController methods
25
-
26
- def get_ticket_actions(self, req, ticket):
27
- """Finds the actions that use this operation"""
28
- controller = ConfigurableTicketWorkflow(self.env)
29
- return controller.get_actions_by_operation_for_req(req, ticket,
30
- self._op_name)
31
-
32
- def get_all_status(self):
33
- """Provide any additional status values"""
34
- # We don't have anything special here; the statuses will be recognized
35
- # by the default controller.
36
- return []
37
-
38
- # This should most likely be overridden to be more functional
39
- def render_ticket_action_control(self, req, ticket, action):
40
- """Returns the action control"""
41
- actions = ConfigurableTicketWorkflow(self.env).actions
42
- label = actions[action]['name']
43
- return (label, tag(''), '')
44
-
45
- def get_ticket_changes(self, req, ticket, action):
46
- """Must be implemented in subclasses"""
47
- raise NotImplementedError
48
-
49
- def apply_action_side_effects(self, req, ticket, action):
50
- """No side effects"""
51
- pass
52
-
53
-
54
- class TicketWorkflowOpOwnerReporter(TicketWorkflowOpBase):
55
- """Sets the owner to the reporter of the ticket.
56
-
57
- needinfo = * -> needinfo
58
- needinfo.name = Need info
59
- needinfo.operations = set_owner_to_reporter
60
-
61
-
62
- Don't forget to add the `TicketWorkflowOpOwnerReporter` to the workflow
63
- option in [ticket].
64
- If there is no workflow option, the line will look like this:
65
-
66
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpOwnerReporter
67
- """
68
-
69
- _op_name = 'set_owner_to_reporter'
70
-
71
- # ITicketActionController methods
72
-
73
- def render_ticket_action_control(self, req, ticket, action):
74
- """Returns the action control"""
75
- actions = ConfigurableTicketWorkflow(self.env).actions
76
- label = actions[action]['name']
77
- hint = 'The owner will change to %s' % ticket['reporter']
78
- control = tag('')
79
- return (label, control, hint)
80
-
81
- def get_ticket_changes(self, req, ticket, action):
82
- """Returns the change of owner."""
83
- return {'owner': ticket['reporter']}
84
-
85
-
86
- class TicketWorkflowOpOwnerComponent(TicketWorkflowOpBase):
87
- """Sets the owner to the default owner for the component.
88
-
89
- <someaction>.operations = set_owner_to_component_owner
90
-
91
- Don't forget to add the `TicketWorkflowOpOwnerComponent` to the workflow
92
- option in [ticket].
93
- If there is no workflow option, the line will look like this:
94
-
95
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpOwnerComponent
96
- """
97
-
98
- _op_name = 'set_owner_to_component_owner'
99
-
100
- # ITicketActionController methods
101
-
102
- def render_ticket_action_control(self, req, ticket, action):
103
- """Returns the action control"""
104
- actions = ConfigurableTicketWorkflow(self.env).actions
105
- label = actions[action]['name']
106
- hint = 'The owner will change to %s' % self._new_owner(ticket)
107
- control = tag('')
108
- return (label, control, hint)
109
-
110
- def get_ticket_changes(self, req, ticket, action):
111
- """Returns the change of owner."""
112
- return {'owner': self._new_owner(ticket)}
113
-
114
- def _new_owner(self, ticket):
115
- """Determines the new owner"""
116
- component = model.Component(self.env, name=ticket['component'])
117
- self.env.log.debug("component %s, owner %s" % (component, component.owner))
118
- return component.owner
119
-
120
-
121
- class TicketWorkflowOpOwnerField(TicketWorkflowOpBase):
122
- """Sets the owner to the value of a ticket field
123
-
124
- <someaction>.operations = set_owner_to_field
125
- <someaction>.set_owner_to_field = myfield
126
-
127
- Don't forget to add the `TicketWorkflowOpOwnerField` to the workflow
128
- option in [ticket].
129
- If there is no workflow option, the line will look like this:
130
-
131
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpOwnerField
132
- """
133
-
134
- _op_name = 'set_owner_to_field'
135
-
136
- # ITicketActionController methods
137
-
138
- def render_ticket_action_control(self, req, ticket, action):
139
- """Returns the action control"""
140
- actions = ConfigurableTicketWorkflow(self.env).actions
141
- label = actions[action]['name']
142
- hint = 'The owner will change to %s' % self._new_owner(action, ticket)
143
- control = tag('')
144
- return (label, control, hint)
145
-
146
- def get_ticket_changes(self, req, ticket, action):
147
- """Returns the change of owner."""
148
- return {'owner': self._new_owner(action, ticket)}
149
-
150
- def _new_owner(self, action, ticket):
151
- """Determines the new owner"""
152
- # Should probably do some sanity checking...
153
- field = self.config.get('ticket-workflow',
154
- action + '.' + self._op_name).strip()
155
- return ticket[field]
156
-
157
-
158
- class TicketWorkflowOpOwnerPrevious(TicketWorkflowOpBase):
159
- """Sets the owner to the previous owner
160
-
161
- Don't forget to add the `TicketWorkflowOpOwnerPrevious` to the workflow
162
- option in [ticket].
163
- If there is no workflow option, the line will look like this:
164
-
165
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpOwnerPrevious
166
- """
167
-
168
- _op_name = 'set_owner_to_previous'
169
-
170
- # ITicketActionController methods
171
-
172
- def render_ticket_action_control(self, req, ticket, action):
173
- """Returns the action control"""
174
- actions = ConfigurableTicketWorkflow(self.env).actions
175
- label = actions[action]['name']
176
- new_owner = self._new_owner(ticket)
177
- if new_owner:
178
- hint = 'The owner will change to %s' % new_owner
179
- else:
180
- hint = 'The owner will be deleted.'
181
- control = tag('')
182
- return (label, control, hint)
183
-
184
- def get_ticket_changes(self, req, ticket, action):
185
- """Returns the change of owner."""
186
- return {'owner': self._new_owner(ticket)}
187
-
188
- def _new_owner(self, ticket):
189
- """Determines the new owner"""
190
- db = self.env.get_db_cnx()
191
- cursor = db.cursor()
192
- cursor.execute("SELECT oldvalue FROM ticket_change WHERE ticket=%s " \
193
- "AND field='owner' ORDER BY -time", (ticket.id, ))
194
- row = cursor.fetchone()
195
- if row:
196
- owner = row[0]
197
- else: # The owner has never changed.
198
- owner = ''
199
- return owner
200
-
201
-
202
- class TicketWorkflowOpStatusPrevious(TicketWorkflowOpBase):
203
- """Sets the status to the previous status
204
-
205
- Don't forget to add the `TicketWorkflowOpStatusPrevious` to the workflow
206
- option in [ticket].
207
- If there is no workflow option, the line will look like this:
208
-
209
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpStatusPrevious
210
- """
211
-
212
- _op_name = 'set_status_to_previous'
213
-
214
- # ITicketActionController methods
215
-
216
- def render_ticket_action_control(self, req, ticket, action):
217
- """Returns the action control"""
218
- actions = ConfigurableTicketWorkflow(self.env).actions
219
- label = actions[action]['name']
220
- new_status = self._new_status(ticket)
221
- if new_status != ticket['status']:
222
- hint = 'The status will change to %s' % new_status
223
- else:
224
- hint = ''
225
- control = tag('')
226
- return (label, control, hint)
227
-
228
- def get_ticket_changes(self, req, ticket, action):
229
- """Returns the change of status."""
230
- return {'status': self._new_status(ticket)}
231
-
232
- def _new_status(self, ticket):
233
- """Determines the new status"""
234
- db = self.env.get_db_cnx()
235
- cursor = db.cursor()
236
- cursor.execute("SELECT oldvalue FROM ticket_change WHERE ticket=%s " \
237
- "AND field='status' ORDER BY -time", (ticket.id, ))
238
- row = cursor.fetchone()
239
- if row:
240
- status = row[0]
241
- else: # The status has never changed.
242
- status = 'new'
243
- return status
244
-
245
-
246
- class TicketWorkflowOpRunExternal(Component):
247
- """Action to allow running an external command as a side-effect.
248
-
249
- If it is a lengthy task, it should daemonize so the webserver can get back
250
- to doing its thing. If the script exits with a non-zero return code, an
251
- error will be logged to the Trac log.
252
- The plugin will look for a script named <tracenv>/hooks/<someaction>, and
253
- will pass it 2 parameters: the ticket number, and the user.
254
-
255
- <someaction>.operations = run_external
256
- <someaction>.run_external = Hint for the user
257
-
258
- Don't forget to add the `TicketWorkflowOpRunExternal` to the workflow
259
- option in [ticket].
260
- If there is no workflow option, the line will look like this:
261
-
262
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpRunExternal
263
- """
264
-
265
- implements(ITicketActionController)
266
-
267
- # ITicketActionController methods
268
-
269
- def get_ticket_actions(self, req, ticket):
270
- """Finds the actions that use this operation"""
271
- controller = ConfigurableTicketWorkflow(self.env)
272
- return controller.get_actions_by_operation_for_req(req, ticket,
273
- 'run_external')
274
-
275
- def get_all_status(self):
276
- """Provide any additional status values"""
277
- # We don't have anything special here; the statuses will be recognized
278
- # by the default controller.
279
- return []
280
-
281
- def render_ticket_action_control(self, req, ticket, action):
282
- """Returns the action control"""
283
- actions = ConfigurableTicketWorkflow(self.env).actions
284
- label = actions[action]['name']
285
- hint = self.config.get('ticket-workflow',
286
- action + '.run_external').strip()
287
- if hint is None:
288
- hint = "Will run external script."
289
- return (label, tag(''), hint)
290
-
291
- def get_ticket_changes(self, req, ticket, action):
292
- """No changes to the ticket"""
293
- return {}
294
-
295
- def apply_action_side_effects(self, req, ticket, action):
296
- """Run the external script"""
297
- script = os.path.join(self.env.path, 'hooks', action)
298
- retval = call([script, str(ticket.id), req.authname])
299
- if retval:
300
- self.env.log.error("External script %r exited with return code %s." % (script, retval))
301
-
302
-
303
- class TicketWorkflowOpTriage(TicketWorkflowOpBase):
304
- """Action to split a workflow based on a field
305
-
306
- <someaction> = somestatus -> *
307
- <someaction>.operations = triage
308
- <someaction>.triage_field = type
309
- <someaction>.traige_split = defect -> new_defect, task -> new_task, enhancement -> new_enhancement
310
-
311
- Don't forget to add the `TicketWorkflowOpTriage` to the workflow option in
312
- [ticket].
313
- If there is no workflow option, the line will look like this:
314
-
315
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpTriage
316
- """
317
-
318
- _op_name = 'triage'
319
-
320
- # ITicketActionController methods
321
-
322
- def render_ticket_action_control(self, req, ticket, action):
323
- """Returns the action control"""
324
- actions = ConfigurableTicketWorkflow(self.env).actions
325
- label = actions[action]['name']
326
- new_status = self._new_status(ticket, action)
327
- if new_status != ticket['status']:
328
- hint = 'The status will change.'
329
- else:
330
- hint = ''
331
- control = tag('')
332
- return (label, control, hint)
333
-
334
- def get_ticket_changes(self, req, ticket, action):
335
- """Returns the change of status."""
336
- return {'status': self._new_status(ticket, action)}
337
-
338
- def _new_status(self, ticket, action):
339
- """Determines the new status"""
340
- field = self.config.get('ticket-workflow',
341
- action + '.triage_field').strip()
342
- transitions = self.config.get('ticket-workflow',
343
- action + '.triage_split').strip()
344
- for transition in [x.strip() for x in transitions.split(',')]:
345
- value, status = [y.strip() for y in transition.split('->')]
346
- if value == ticket[field].strip():
347
- break
348
- else:
349
- self.env.log.error("Bad configuration for 'triage' operation in action '%s'" % action)
350
- status = 'new'
351
- return status
352
-
353
-
354
- class TicketWorkflowOpXRef(TicketWorkflowOpBase):
355
- """Adds a cross reference to another ticket
356
-
357
- <someaction>.operations = xref
358
- <someaction>.xref = "Ticket %s is related to this ticket"
359
- <someaction>.xref_local = "Ticket %s was marked as related to this ticket"
360
- <someaction>.xref_hint = "The specified ticket will be cross-referenced with this ticket"
361
-
362
- The example values shown are the default values.
363
- Don't forget to add the `TicketWorkflowOpXRef` to the workflow
364
- option in [ticket].
365
- If there is no workflow option, the line will look like this:
366
-
367
- workflow = ConfigurableTicketWorkflow,TicketWorkflowOpXRef
368
- """
369
-
370
- _op_name = 'xref'
371
-
372
- # ITicketActionController methods
373
-
374
- def render_ticket_action_control(self, req, ticket, action):
375
- """Returns the action control"""
376
- id = 'action_%s_xref' % action
377
- ticketnum = req.args.get(id, '')
378
- actions = ConfigurableTicketWorkflow(self.env).actions
379
- label = actions[action]['name']
380
- hint = actions[action].get('xref_hint',
381
- 'The specified ticket will be cross-referenced with this ticket')
382
- control = tag.input(type='text', id=id, name=id, value=ticketnum)
383
- return (label, control, hint)
384
-
385
- def get_ticket_changes(self, req, ticket, action):
386
- """Returns no changes."""
387
- return {}
388
-
389
- def apply_action_side_effects(self, req, ticket, action):
390
- """Add a cross-reference comment to the other ticket"""
391
- # TODO: This needs a lot more error checking.
392
- id = 'action_%s_xref' % action
393
- ticketnum = req.args.get(id).strip('#')
394
- actions = ConfigurableTicketWorkflow(self.env).actions
395
- author = req.authname
396
-
397
- # Add a comment to the "remote" ticket to indicate this ticket is
398
- # related to it.
399
- format_string = actions[action].get('xref',
400
- 'Ticket %s is related to this ticket')
401
- comment = format_string % ('#%s' % ticket.id)
402
- # FIXME: This assumes the referenced ticket exists.
403
- xticket = model.Ticket(self.env, ticketnum)
404
- # FIXME: We _assume_ we have sufficient permissions to comment on the
405
- # other ticket.
406
- xticket.save_changes(author, comment)
407
-
408
- # Add a comment to this ticket to indicate that the "remote" ticket is
409
- # related to it. (But only if <action>.xref_local was set in the
410
- # config.)
411
- format_string = actions[action].get('xref_local',
412
- 'Ticket %s was marked as related to this ticket')
413
- if format_string:
414
- comment = format_string % ('#%s' % ticketnum)
415
- time.sleep(1) # FIXME: Hack around IntegrityError
416
- # HACK: Grab a new ticket object to avoid getting
417
- # "OperationalError: no such column: new"
418
- xticket = model.Ticket(self.env, ticket.id)
419
- xticket.save_changes(author, comment)
@@ -1,3 +0,0 @@
1
- [egg_info]
2
- tag_build = dev
3
- tag_svn_revision = true
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- from setuptools import setup, find_packages
4
-
5
- setup(
6
- name='AdvancedTicketWorkflowPlugin',
7
- version='0.10',
8
- author = 'Eli Carter',
9
- author_email = 'elicarter@retracile.net',
10
- license='BSD',
11
- description = 'Advanced workflow operations Trac plugin',
12
- long_description = 'Provides more advanced workflow operations',
13
- url = 'http://trac-hacks.org/wiki/AdvancedTicketWorkflowPlugin',
14
-
15
- packages = find_packages(),
16
- package_data = {},
17
- entry_points = {'trac.plugins':['advancedworkflow.controller = advancedworkflow.controller']},
18
- install_requires = [],
19
- #zip_safe = False,
20
- )
@@ -1,28 +0,0 @@
1
- from lxml import etree
2
- from trac.core import *
3
-
4
- class IClientActionProvider(Interface):
5
- """Extension point interface for components that define their own way
6
- to act on a given client summary (IClientSummaryProvider.get_summary
7
- """
8
-
9
- def get_name():
10
- """Return the name of the action (for use in UI)
11
- """
12
-
13
- def get_description():
14
- """Return the description of the action (for use in UI)
15
- """
16
-
17
- def options(client=None):
18
- """The options for this action
19
- If the client option is None then these options are defined as being per instance.
20
- """
21
-
22
- def init(event, client):
23
- """Todo
24
- """
25
-
26
- def perform(req, summary):
27
- """Perform the action. This must return an etree object
28
- """