Ticket #1396: TicketClosePermissions.diff
| File TicketClosePermissions.diff, 13.0 KB (added by ludde, 4 years ago) |
|---|
-
trac/attachment.py
63 63 self.render_view(req, parent_type, parent_id, filename) 64 64 65 65 def render_form(self, req, parent_type, parent_id): 66 perm_map = {'ticket': perm.TICKET_ MODIFY, 'wiki': perm.WIKI_MODIFY}66 perm_map = {'ticket': perm.TICKET_ATTACH, 'wiki': perm.WIKI_MODIFY} 67 67 self.perm.assert_permission(perm_map[parent_type]) 68 68 69 69 text, link = self.get_parent_link(parent_type, parent_id) … … 79 79 req.display('attachment.cs') 80 80 81 81 def save_attachment(self, req, parent_type, parent_id): 82 perm_map = {'ticket': perm.TICKET_ MODIFY, 'wiki': perm.WIKI_MODIFY}82 perm_map = {'ticket': perm.TICKET_ATTACH, 'wiki': perm.WIKI_MODIFY} 83 83 self.perm.assert_permission(perm_map[parent_type]) 84 84 85 85 if req.args.has_key('cancel'): -
trac/perm.py
24 24 'TIMELINE_VIEW', 'SEARCH_VIEW', 'CONFIG_VIEW', 'LOG_VIEW', 'FILE_VIEW', 25 25 'CHANGESET_VIEW', 'BROWSER_VIEW', 'ROADMAP_VIEW', 26 26 27 'TICKET_VIEW', 'TICKET_CREATE', 'TICKET_MODIFY', 27 'TICKET_VIEW', 'TICKET_CREATE', 'TICKET_EDIT', 'TICKET_RESOLVE', 28 'TICKET_APPEND','TICKET_ATTACH', 28 29 29 30 'REPORT_VIEW', 'REPORT_SQL_VIEW', 'REPORT_CREATE', 'REPORT_MODIFY', 30 31 'REPORT_DELETE', … … 39 40 'TRAC_ADMIN': ['TICKET_ADMIN', 'REPORT_ADMIN', 'WIKI_ADMIN', 'ROADMAP_ADMIN', 40 41 'TIMELINE_VIEW', 'SEARCH_VIEW', 'CONFIG_VIEW', 'LOG_VIEW', 41 42 'FILE_VIEW', 'CHANGESET_VIEW', 'BROWSER_VIEW'], 42 'TICKET_ADMIN': ['TICKET_VIEW', 'TICKET_CREATE', 'TICKET_MODIFY'], 43 'TICKET_ADMIN': ['TICKET_VIEW', 'TICKET_CREATE', 'TICKET_EDIT', 44 'TICKET_RESOLVE', 'TICKET_ATTACH'], 45 'TICKET_MODIFY': ['TICKET_EDIT', 'TICKET_RESOLVE', 'TICKET_ATTACH'], 43 46 'REPORT_ADMIN': ['REPORT_VIEW', 'REPORT_SQL_VIEW', 'REPORT_CREATE', 44 47 'REPORT_MODIFY', 'REPORT_DELETE'], 45 48 'WIKI_ADMIN': ['WIKI_VIEW', 'WIKI_CREATE', 'WIKI_MODIFY', 'WIKI_DELETE'], -
trac/Ticket.py
78 78 for row in rows: 79 79 self['custom_' + row[0]] = row[1] 80 80 self._forget_changes() 81 81 82 82 def populate(self, dict): 83 83 """Populate the ticket with 'suitable' values from a dictionary""" 84 84 def is_field(name): … … 210 210 log.append((int(row[0]), row[1], row[2], row[3] or '', row[4] or '')) 211 211 return log 212 212 213 214 213 def get_custom_fields(env): 215 214 cfg = env.get_config_items('ticket-custom') 216 215 if not cfg: … … 368 367 369 368 req.display('newticket.cs') 370 369 370 def get_ticket_actions(ticket, prm): 371 """ Returns the actions that can be performed on the ticket""" 372 actions = { 373 'new': ['leave', 'resolve', 'reassign', 'accept'], 374 'assigned': ['leave', 'resolve', 'reassign' ], 375 'reopened': ['leave', 'resolve', 'reassign' ], 376 'closed': ['leave', 'reopen'] 377 } 378 permissions = { 379 'resolve': perm.TICKET_RESOLVE, 380 'reassign': perm.TICKET_EDIT, 381 'accept': perm.TICKET_EDIT, 382 'reopen': perm.TICKET_CREATE 383 } 384 def has_perm(p): 385 n = permissions.get(p, None) 386 return not n or prm.has_permission(n) 387 return filter(has_perm, actions.get(ticket['status'], ['leave'])) 371 388 372 class TicketModule (Module): 373 389 class TicketModule (Module): 390 374 391 def save_changes(self, req, id): 375 self.perm.assert_permission (perm.TICKET_MODIFY) 376 ticket = Ticket(self.db, id) 377 378 if not req.args.get('summary'): 379 raise util.TracError('Tickets must contain Summary.') 380 381 if req.args.has_key('description'): 382 self.perm.assert_permission (perm.TICKET_ADMIN) 383 384 if req.args.has_key('reporter'): 385 self.perm.assert_permission (perm.TICKET_ADMIN) 386 387 # TODO: this should not be hard-coded like this 388 action = req.args.get('action', None) 389 if action == 'accept': 390 ticket['status'] = 'assigned' 391 ticket['owner'] = req.authname 392 if action == 'resolve': 393 ticket['status'] = 'closed' 394 ticket['resolution'] = req.args.get('resolve_resolution') 395 elif action == 'reassign': 396 ticket['owner'] = req.args.get('reassign_owner') 397 ticket['status'] = 'new' 398 elif action == 'reopen': 399 ticket['status'] = 'reopened' 400 ticket['resolution'] = '' 401 402 ticket.populate(req.args) 403 392 if self.perm.has_permission(perm.TICKET_EDIT): 393 # TICKET_EDIT gives permission to edit the ticket 394 if not req.args.get('summary'): 395 raise util.TracError('Tickets must contain Summary.') 396 397 ticket = Ticket(self.db, id) 398 if req.args.has_key('description'): 399 self.perm.assert_permission (perm.TICKET_ADMIN) 400 401 if req.args.has_key('reporter'): 402 self.perm.assert_permission (perm.TICKET_ADMIN) 403 404 ticket.populate(req.args) 405 406 elif self.perm.has_permission(perm.TICKET_APPEND): 407 # Allow appending a comment to the ticket only 408 ticket = Ticket(self.db, id) 409 else: 410 raise perm.PermissionError(perm.TICKET_EDIT) 411 412 # Do any action on the ticket? 413 action = req.args.get('action', None) 414 415 # Make sure the action is valid 416 if action not in get_ticket_actions(ticket, self.perm): 417 raise util.TracError('Invalid action') 418 419 # TODO: this should not be hard-coded like this 420 if action == 'accept': 421 ticket['status'] = 'assigned' 422 ticket['owner'] = req.authname 423 if action == 'resolve': 424 ticket['status'] = 'closed' 425 ticket['resolution'] = req.args.get('resolve_resolution') 426 elif action == 'reassign': 427 ticket['owner'] = req.args.get('reassign_owner') 428 ticket['status'] = 'new' 429 elif action == 'reopen': 430 ticket['status'] = 'reopened' 431 ticket['resolution'] = '' 432 404 433 now = int(time.time()) 405 434 ticket.save_changes(self.db, req.args.get('author', req.authname), 406 435 req.args.get('comment'), when=now) … … 493 522 # List attached files 494 523 self.env.get_attachments_hdf(self.db, 'ticket', str(id), req.hdf, 495 524 'ticket.attachments') 496 req.hdf['ticket.attach_href'] = self.env.href.attachment('ticket', id) 525 if self.perm.has_permission(perm.TICKET_ATTACH): 526 req.hdf['ticket.attach_href'] = self.env.href.attachment('ticket', id) 527 528 # Add the possible workflow paths to hdf 529 for action in get_ticket_actions(ticket,self.perm): 530 req.hdf['ticket.workflow.' + action] = '1' 497 531 498 532 def render(self, req): 499 533 self.perm.assert_permission (perm.TICKET_VIEW) … … 530 564 else: 531 565 req.hdf['ticket.reassign_owner'] = req.authname 532 566 533 self.insert_ticket_data(req, id, ticket, reporter_id) 567 self.insert_ticket_data(req, id, ticket, reporter_id) 534 568 535 569 # If the ticket is being shown in the context of a query, add 536 570 # links to help navigate in the query result set -
templates/ticket.cs
128 128 /each ?></div><?cs 129 129 /if ?> 130 130 131 <?cs if $trac.acl.TICKET_ MODIFY?>131 <?cs if $trac.acl.TICKET_EDIT || $trac.acl.TICKET_APPEND ?> 132 132 <form action="<?cs var:cgi_location ?>#preview" method="post"> 133 133 <hr /> 134 134 <h3><a name="edit" onfocus="document.getElementById('comment').focus()">Add/Change #<?cs … … 155 155 /if ?> 156 156 </div> 157 157 158 <?cs if $trac.acl.TICKET_EDIT ?> 158 159 <fieldset id="properties"> 159 160 <legend>Change Properties</legend> 160 161 <div class="main"> … … 203 204 <?cs call:ticket_custom_props(ticket) ?> 204 205 </div><?cs /if ?> 205 206 </fieldset> 207 <?cs /if ?> 206 208 209 <?cs if ticket.workflow.accept || ticket.workflow.reopen || ticket.workflow.resolve || ticket.workflow.reassign ?> 207 210 <fieldset id="action"> 208 211 <legend>Action</legend><?cs 209 212 if:!ticket.action ?><?cs set:ticket.action = 'leave' ?><?cs … … 214 217 /if ?> /><?cs 215 218 /def ?> 216 219 <?cs call:action_radio('leave') ?> 217 <label for="leave">leave as <?cs var:ticket.status ?></label><br /><?cs218 if $ticket.status == "new" ?>219 <?cscall:action_radio('accept') ?>220 <label for="accept">accept ticket</label><br /><?cs220 <label for="leave">leave as <?cs var:ticket.status ?></label><br /><?cs 221 if ticket.workflow.accept ?><?cs 222 call:action_radio('accept') ?> 223 <label for="accept">accept ticket</label><br /><?cs 221 224 /if ?><?cs 222 if $ticket.status == "closed" ?>223 <?cscall:action_radio('reopen') ?>224 <label for="reopen">reopen ticket</label><br /><?cs225 if ticket.workflow.reopen ?><?cs 226 call:action_radio('reopen') ?> 227 <label for="reopen">reopen ticket</label><br /><?cs 225 228 /if ?><?cs 226 if $ticket.status == "new" || $ticket.status == "assigned" || $ticket.status == "reopened" ?> 227 <?cs call:action_radio('resolve') ?> 228 <label for="resolve">resolve</label> 229 <label for="resolve_resolution">as:</label> 230 <?cs call:hdf_select(enums.resolution, "resolve_resolution", args.resolve_resolution, 0) ?><br /> 231 <?cs call:action_radio('reassign') ?> 232 <label for="reassign">reassign</label> 233 <label>to:<?cs 234 if:len(ticket.users) ?><?cs 235 call:hdf_select(ticket.users, "reassign_owner", ticket.reassign_owner, 0) ?><?cs 236 else ?> 237 <input type="text" id="reassign_owner" name="reassign_owner" size="40" value="<?cs 238 var:ticket.reassign_owner ?>" /><?cs 239 /if ?></label><?cs 229 if ticket.workflow.resolve ?><?cs 230 call:action_radio('resolve') ?> 231 <label for="resolve">resolve</label> 232 <label for="resolve_resolution">as:</label> 233 <?cs call:hdf_select(enums.resolution, "resolve_resolution", args.resolve_resolution, 0) ?><br /><?cs 240 234 /if ?><?cs 241 if $ticket.status == "new" || $ticket.status == "assigned" || $ticket.status == "reopened" ?> 242 <script type="text/javascript"> 243 var resolve = document.getElementById("resolve"); 244 var reassign = document.getElementById("reassign"); 245 var updateActionFields = function() { 246 enableControl('resolve_resolution', resolve.checked); 247 enableControl('reassign_owner', reassign.checked); 235 if ticket.workflow.reassign ?><?cs 236 call:action_radio('reassign') ?> 237 <label for="reassign">reassign</label> 238 <label>to:<?cs 239 if:len(ticket.users) ?><?cs 240 call:hdf_select(ticket.users, "reassign_owner", ticket.reassign_owner, 0) ?><?cs 241 else ?> 242 <input type="text" id="reassign_owner" name="reassign_owner" size="40" value="<?cs 243 var:ticket.reassign_owner ?>" /><?cs 244 /if ?></label><?cs 245 /if ?><?cs 246 if ticket.workflow.resolve || ticket.workflow.reassign ?> 247 <script type="text/javascript"><?cs 248 if ticket.workflow.resolve ?> 249 var resolve = document.getElementById("resolve");<?cs 250 /if ?><?cs 251 if ticket.workflow.reassign ?> 252 var reassign = document.getElementById("reassign");<?cs 253 /if ?> 254 var updateActionFields = function() {<?cs 255 if ticket.workflow.resolve ?> 256 enableControl('resolve_resolution', resolve.checked);<?cs 257 /if ?><?cs 258 if ticket.workflow.reassign ?> 259 enableControl('reassign_owner', reassign.checked);<?cs 260 /if ?> 248 261 }; 249 262 addEvent(window, 'load', updateActionFields); 250 263 addEvent(document.getElementById("leave"), 'click', updateActionFields);<?cs 251 if $ticket.status == "new"?>264 if ticket.workflow.accept ?> 252 265 addEvent(document.getElementById("accept"), 'click', updateActionFields);<?cs 253 /if ?> 254 addEvent(resolve, 'click', updateActionFields); 255 addEvent(reassign, 'click', updateActionFields); 266 /if ?><?cs 267 if ticket.workflow.resolve ?> 268 addEvent(resolve, 'click', updateActionFields);<?cs 269 /if ?><?cs 270 if ticket.workflow.reopen ?> 271 addEvent(document.getElementById("reopen"), 'click', updateActionFields);<?cs 272 /if ?><?cs 273 if ticket.workflow.reassign ?> 274 addEvent(reassign, 'click', updateActionFields);<?cs 275 /if ?> 256 276 </script><?cs 257 277 /if ?> 258 278 </fieldset> 279 <?cs else ?> 280 <input type="hidden" name="action" value="leave" /> 281 <?cs /if ?> 259 282 260 283 <script type="text/javascript" src="<?cs 261 284 var:htdocs_location ?>js/wikitoolbar.js"></script> … … 263 286 <div class="buttons"> 264 287 <input type="reset" value="Reset" /> 265 288 <input type="submit" name="preview" value="Preview" /> 266 <input type="submit" value="Submit changes" /> 289 <input type="submit" value="Submit changes" /> 267 290 </div> 268 291 </form> 269 292 <?cs /if ?>
