root/adminconsoleproviderpatch/0.9/admin-provider-refactor.diff
| Revision 96, 62.8 kB (checked in by athomas, 3 years ago) |
|---|
-
trac/ticket/api.py
old new 26 26 from trac.perm import IPermissionRequestor 27 27 from trac.wiki import IWikiSyntaxProvider 28 28 from trac.Search import ISearchSource, query_to_sql, shorten_result 29 from trac.scripts.admin import IAdminConsoleProvider 29 30 30 31 31 class MyLinkResolver(Component): 32 32 """ 33 33 A dummy macro used by the unit test. We need to supply our own macro … … 200 200 date, author, 201 201 util.escape(shorten_result(desc, query.split()))) 202 202 203 class TicketAdminConsole(Component): 204 """ Provides trac-admin with ticket related commands """ 205 206 # IAdminConsoleProvider methods 207 implements(IAdminConsoleProvider) 208 209 def get_console_commands(self, tracadm): 210 self.tracadm = tracadm 211 from trac.ticket.model import Type, Priority, Severity 212 self._enum_map = {'ticket_type': Type, 'priority': Priority, 213 'severity': Severity } 214 215 yield ('ticket_type', self._help_ticket_type, self.do_ticket_type, self.complete_ticket_type) 216 yield ('severity', self._help_severity, self.do_severity, self.complete_severity) 217 yield ('priority', self._help_priority, self.do_priority, self.complete_priority) 218 yield ('component', self._help_component, self.do_component, self.complete_component) 219 yield ('version', [('version list', 'Show versions'), 220 ('version add <name> [time]', 'Add version'), 221 ('version rename <name> <newname>', 222 'Rename version'), 223 ('version time <name> <time>', 224 'Set version date (Format: "%s" or "now")' 225 % tracadm._date_format_hint), 226 ('version remove <name>', 'Remove version')], 227 self.do_version, self.complete_version) 228 229 230 231 ## (Ticket) Type 232 _help_ticket_type = [('ticket_type list', 'Show possible ticket types'), 233 ('ticket_type add <value>', 'Add a ticket type'), 234 ('ticket_type change <value> <newvalue>', 235 'Change a ticket type'), 236 ('ticket_type remove <value>', 'Remove a ticket type')] 237 238 def complete_ticket_type (self, text, line, begidx, endidx): 239 if begidx == 16: 240 comp = self.get_enum_list ('ticket_type') 241 elif begidx < 15: 242 comp = ['list', 'add', 'change', 'remove'] 243 return self.tracadm.word_complete(text, comp) 244 245 def do_ticket_type(self, line): 246 self._do_enum('ticket_type', line) 247 248 ## (Ticket) Priority 249 _help_priority = [('priority list', 'Show possible ticket priorities'), 250 ('priority add <value>', 'Add a priority value option'), 251 ('priority change <value> <newvalue>', 252 'Change a priority value'), 253 ('priority remove <value>', 'Remove priority value')] 254 255 def complete_priority (self, text, line, begidx, endidx): 256 if begidx == 16: 257 comp = self.get_enum_list ('priority') 258 elif begidx < 15: 259 comp = ['list', 'add', 'change', 'remove'] 260 return self.tracadm.word_complete(text, comp) 261 262 def do_priority(self, line): 263 self._do_enum('priority', line) 264 265 ## (Ticket) Severity 266 _help_severity = [('severity list', 'Show possible ticket severities'), 267 ('severity add <value>', 'Add a severity value option'), 268 ('severity change <value> <newvalue>', 269 'Change a severity value'), 270 ('severity remove <value>', 'Remove severity value')] 271 272 def complete_severity (self, text, line, begidx, endidx): 273 if begidx == 16: 274 comp = self.get_enum_list ('severity') 275 elif begidx < 15: 276 comp = ['list', 'add', 'change', 'remove'] 277 return self.tracadm.word_complete(text, comp) 278 279 def do_severity(self, line): 280 self._do_enum('severity', line) 281 282 # Type, priority, severity share the same datastructure and methods: 283 284 def _do_enum(self, type, line): 285 arg = self.tracadm.arg_tokenize(line) 286 try: 287 if arg[0] == 'list': 288 self._do_enum_list(type) 289 elif arg[0] == 'add' and len(arg)==2: 290 name = arg[1] 291 self._do_enum_add(type, name) 292 elif arg[0] == 'change' and len(arg)==3: 293 name = arg[1] 294 newname = arg[2] 295 self._do_enum_change(type, name, newname) 296 elif arg[0] == 'remove' and len(arg)==2: 297 name = arg[1] 298 self._do_enum_remove(type, name) 299 else: 300 self.tracadm.do_help (type) 301 except Exception, e: 302 print 'Command %s failed:' % arg[0], e 303 304 def _do_enum_list(self, type): 305 enum_cls = self._enum_map[type] 306 self.tracadm.print_listing(['Possible Values'], 307 [(e.name,) for e in enum_cls.select(self.tracadm.env_open())]) 308 309 def _do_enum_add(self, type, name): 310 sql = ("INSERT INTO enum(value,type,name) " 311 " SELECT 1+COALESCE(max(value),0),'%(type)s','%(name)s'" 312 " FROM enum WHERE type='%(type)s'" 313 % {'type':type, 'name':name}) 314 self.tracadm.db_update(sql) 315 316 def _do_enum_change(self, type, name, newname): 317 enum_cls = self._enum_map[type] 318 enum = enum_cls(self.tracadm.env_open(), name) 319 enum.name = newname 320 enum.update() 321 322 def _do_enum_remove(self, type, name): 323 enum_cls = self._enum_map[type] 324 enum = enum_cls(self.tracadm.env_open(), name) 325 enum.delete() 326 327 def get_enum_list(self, type): 328 rows = self.tracadm.db_query("SELECT name FROM enum WHERE type='%s'" % type) 329 return [row[0] for row in rows] 330 331 # Component 332 _help_component = [('component list', 'Show available components'), 333 ('component add <name> <owner>', 'Add a new component'), 334 ('component rename <name> <newname>', 335 'Rename a component'), 336 ('component remove <name>', 337 'Remove/uninstall component'), 338 ('component chown <name> <owner>', 339 'Change component ownership')] 340 341 def complete_component(self, text, line, begidx, endidx): 342 if begidx in (16, 17): 343 comp = self.get_component_list() 344 elif begidx > 15 and line.startswith('component chown '): 345 comp = self.get_user_list() 346 else: 347 comp = ['list', 'add', 'rename', 'remove', 'chown'] 348 return self.tracadm.word_complete(text, comp) 349 350 def do_component(self, line): 351 arg = self.tracadm.arg_tokenize(line) 352 try: 353 if arg[0] == 'list': 354 self._do_component_list() 355 elif arg[0] == 'add' and len(arg)==3: 356 name = arg[1] 357 owner = arg[2] 358 self._do_component_add(name, owner) 359 elif arg[0] == 'rename' and len(arg)==3: 360 name = arg[1] 361 newname = arg[2] 362 self._do_component_rename(name, newname) 363 elif arg[0] == 'remove' and len(arg)==2: 364 name = arg[1] 365 self._do_component_remove(name) 366 elif arg[0] == 'chown' and len(arg)==3: 367 name = arg[1] 368 owner = arg[2] 369 self._do_component_set_owner(name, owner) 370 else: 371 self.tracadm.do_help ('component') 372 except Exception, e: 373 print 'Component %s failed:' % arg[0], e 374 375 def _do_component_list(self): 376 from trac.ticket.model import Component 377 data = [] 378 for c in Component.select(self.tracadm.env_open()): 379 data.append((c.name, c.owner)) 380 self.tracadm.print_listing(['Name', 'Owner'], data) 381 382 def _do_component_add(self, name, owner): 383 from trac.ticket.model import Component 384 component = Component(self.tracadm.env_open()) 385 component.name = name 386 component.owner = owner 387 component.insert() 388 389 def _do_component_rename(self, name, newname): 390 from trac.ticket.model import Component 391 component = Component(self.tracadm.env_open(), name) 392 component.name = newname 393 component.update() 394 395 def _do_component_remove(self, name): 396 from trac.ticket.model import Component 397 component = Component(self.tracadm.env_open(), name) 398 component.delete() 399 400 def _do_component_set_owner(self, name, owner): 401 from trac.ticket.model import Component 402 component = Component(self.tracadm.env_open(), name) 403 component.owner = owner 404 component.update() 405 406 def get_user_list(self): 407 rows = self.tracadm.db_query("SELECT DISTINCT username FROM permission") 408 return [row[0] for row in rows] 409 410 def get_component_list(self): 411 rows = self.tracadm.db_query("SELECT name FROM component") 412 return [row[0] for row in rows] 413 414 def complete_version (self, text, line, begidx, endidx): 415 if begidx in (13, 15): 416 comp = self.get_version_list() 417 elif begidx < 13: 418 comp = ['list', 'add', 'rename', 'time', 'remove'] 419 return self.tracadm.word_complete(text, comp) 420 421 def do_version(self, line): 422 arg = self.tracadm.arg_tokenize(line) 423 try: 424 if arg[0] == 'list': 425 self._do_version_list() 426 elif arg[0] == 'add' and len(arg) in [2,3]: 427 self._do_version_add(arg[1]) 428 if len(arg) == 3: 429 self._do_version_time(arg[1], arg[2]) 430 elif arg[0] == 'rename' and len(arg) == 3: 431 self._do_version_rename(arg[1], arg[2]) 432 elif arg[0] == 'time' and len(arg) == 3: 433 self._do_version_time(arg[1], arg[2]) 434 elif arg[0] == 'remove' and len(arg) == 2: 435 self._do_version_remove(arg[1]) 436 else: 437 self.tracadm.do_help('version') 438 except Exception, e: 439 print 'Command %s failed:' % arg[0], e 440 441 def _do_version_list(self): 442 from trac.ticket.model import Version 443 data = [] 444 for v in Version.select(self.tracadm.env_open()): 445 data.append((v.name, v.time and self.tracadm._format_date(v.time))) 446 self.tracadm.print_listing(['Name', 'Time'], data) 447 448 def _do_version_rename(self, name, newname): 449 from trac.ticket.model import Version 450 version = Version(self.tracadm.env_open(), name) 451 version.name = newname 452 version.update() 453 454 def _do_version_add(self, name): 455 from trac.ticket.model import Version 456 version = Version(self.tracadm.env_open()) 457 version.name = name 458 version.insert() 459 460 def _do_version_remove(self, name): 461 from trac.ticket.model import Version 462 version = Version(self.tracadm.env_open(), name) 463 version.delete() 464 465 def _do_version_time(self, name, t): 466 from trac.ticket.model import Version 467 version = Version(self.tracadm.env_open(), name) 468 version.time = self.tracadm._parse_date(t) 469 version.update() 470 471 def get_version_list(self): 472 rows = self.db_query("SELECT name FROM version") 473 return [row[0] for row in rows] -
trac/Milestone.py
old new 30 30 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 31 31 from trac.web.main import IRequestHandler 32 32 from trac.wiki import wiki_to_html, wiki_to_oneliner, IWikiSyntaxProvider 33 from trac.scripts.admin import IAdminConsoleProvider 33 34 34 35 35 class Milestone(object): 36 36 37 37 def __init__(self, env, name=None, db=None): … … 465 465 def _format_link(self, formatter, ns, name, label): 466 466 return '<a class="milestone" href="%s">%s</a>' \ 467 467 % (formatter.href.milestone(name), label) 468 469 470 class MilestoneAdminConsole(Component): 471 """ Provide trac-admin with commands for manipulating milestones """ 472 473 implements(IAdminConsoleProvider) 474 475 # IAdminConsoleProvider methods 476 def get_console_commands(self, tracadm): 477 self.tracadm = tracadm 478 yield ('milestone', [('milestone list', 'Show milestones'), 479 ('milestone add <name> [due]', 'Add milestone'), 480 ('milestone rename <name> <newname>', 481 'Rename milestone'), 482 ('milestone due <name> <due>', 483 'Set milestone due date (Format: "%s" or "now")' 484 % tracadm._date_format_hint), 485 ('milestone completed <name> <completed>', 486 'Set milestone completed date (Format: "%s" or "now")' 487 % tracadm._date_format_hint), 488 ('milestone remove <name>', 'Remove milestone')], 489 self.do_milestone, self.complete_milestone) 490 491 492 def complete_milestone (self, text, line, begidx, endidx): 493 if begidx in (15, 17): 494 comp = self.get_milestone_list() 495 elif begidx < 15: 496 comp = ['list', 'add', 'rename', 'time', 'remove'] 497 return self.tracadm.word_complete(text, comp) 498 499 def do_milestone(self, line): 500 arg = self.tracadm.arg_tokenize(line) 501 try: 502 if arg[0] == 'list': 503 self._do_milestone_list() 504 elif arg[0] == 'add' and len(arg) in [2,3]: 505 self._do_milestone_add(arg[1]) 506 if len(arg) == 3: 507 self._do_milestone_set_due(arg[1], arg[2]) 508 elif arg[0] == 'rename' and len(arg) == 3: 509 self._do_milestone_rename(arg[1], arg[2]) 510 elif arg[0] == 'remove' and len(arg) == 2: 511 self._do_milestone_remove(arg[1]) 512 elif arg[0] == 'due' and len(arg) == 3: 513 self._do_milestone_set_due(arg[1], arg[2]) 514 elif arg[0] == 'completed' and len(arg) == 3: 515 self._do_milestone_set_completed(arg[1], arg[2]) 516 else: 517 self.tracadm.do_help('milestone') 518 except Exception, e: 519 print 'Command %s failed:' % arg[0], e 520 521 def _do_milestone_list(self): 522 data = [] 523 for m in Milestone.select(self.tracadm.env_open()): 524 data.append((m.name, m.due and self.tracadm._format_date(m.due), 525 m.completed and self.tracadm._format_datetime(m.completed))) 526 527 self.tracadm.print_listing(['Name', 'Due', 'Completed'], data) 528 529 def _do_milestone_rename(self, name, newname): 530 milestone = Milestone(self.tracadm.env_open(), name) 531 milestone.name = newname 532 milestone.update() 533 534 def _do_milestone_add(self, name): 535 milestone = Milestone(self.tracadm.env_open()) 536 milestone.name = name 537 milestone.insert() 538 539 def _do_milestone_remove(self, name): 540 milestone = Milestone(self.tracadm.env_open(), name) 541 milestone.delete() 542 543 def _do_milestone_set_due(self, name, t): 544 milestone = Milestone(self.tracadm.env_open(), name) 545 milestone.due = self.tracadm._parse_date(t) 546 milestone.update() 547 548 def _do_milestone_set_completed(self, name, t): 549 milestone = Milestone(self.tracadm.env_open(), name) 550 milestone.completed = self.tracadm._parse_date(t) 551 milestone.update() 552 553 def get_milestone_list(self): 554 rows = self.tracadm.db_query("SELECT name FROM milestone") 555 return [row[0] for row in rows] -
trac/scripts/admin.py
old new 33 33 import urllib 34 34 35 35 import trac 36 from trac import perm,util36 from trac import util 37 37 from trac.config import default_dir 38 38 from trac.env import Environment 39 from trac.Milestone import Milestone 40 from trac.perm import PermissionSystem 41 from trac.ticket.model import * 39 from trac.core import ComponentManager, ExtensionPoint, Interface 40 from trac.loader import load_components 42 41 42 __all__ = [ 'IAdminConsoleProvider' ] 43 43 44 try: 44 45 sum 45 46 except NameError: … … 50 51 tot += item 51 52 return tot 52 53 54 class IAdminConsoleProvider(Interface): 55 """ 56 Extension point interface for components to provide an administrative 57 interface from within trac-admin. 58 """ 53 59 60 def get_console_commands(tracadm): 61 """ 62 Return an iterable of (name, help, callable, completer) tuples. 63 64 tracadm is a TracAdmin instance. 65 66 completer can be null. help is in the same format that trac-admin 67 uses. 68 """ 69 70 class AdminCommands(trac.core.Component): 71 """ 72 Component end-point for IAdminConsoleProvider extensions 73 """ 74 admin_providers = ExtensionPoint(IAdminConsoleProvider) 75 76 def import_providers(self, env, tracadm): 77 load_components(env) 78 for provider in self.admin_providers: 79 for command in provider.get_console_commands(tracadm): 80 name, help, callback, completer = command 81 setattr(tracadm.__class__, 'do_' + name, callback) 82 setattr(tracadm.__class__, '_help_' + name, help) 83 if completer: 84 setattr(tracadm.__class__, 'complete_' + name, completer) 85 54 86 class TracAdmin(cmd.Cmd): 55 87 intro = '' 56 88 license = trac.__license_long__ … … 64 96 _date_format = '%Y-%m-%d' 65 97 _datetime_format = '%Y-%m-%d %H:%M:%S' 66 98 _date_format_hint = 'YYYY-MM-DD' 99 _admin_commands = None 67 100 68 101 def __init__(self, envdir=None): 69 102 cmd.Cmd.__init__(self) … … 72 105 self.env_set(os.path.abspath(envdir)) 73 106 74 107 def docmd(self, cmd='help'): 108 self.env_check() 75 109 self.onecmd(cmd) 76 110 77 111 def emptyline(self): … … 84 118 '%(copy)s\n\n' \ 85 119 "Type: '?' or 'help' for help on commands.\n" % \ 86 120 {'ver':trac.__version__,'copy':__copyright__} 121 self.env_check() 87 122 self.cmdloop() 88 123 89 124 ## … … 99 134 def env_check(self): 100 135 try: 101 136 self.__env = Environment(self.envname) 102 except: 137 try: 138 self._admin_commands = AdminCommands(self.__env) 139 self._admin_commands.import_providers(self.__env, self) 140 except Exception, e: 141 print "Failed to initialise extension points.", e 142 raise 143 except Exception, e: 103 144 return 0 104 145 return 1 105 146 106 147 def env_create(self, db_str): 107 148 try: 108 149 self.__env = Environment(self.envname, create=True, db_str=db_str) 150 self._admin_commands = AdminCommands(self.__env) 151 self._admin_commands.import_providers(self.__env, self) 109 152 return self.__env 110 153 except Exception, e: 111 154 print 'Failed to create environment.', e … … 117 160 try: 118 161 if not self.__env: 119 162 self.__env = Environment(self.envname) 163 self._admin_commands = AdminCommands(self.__env) 164 self._admin_commands.import_providers(self.__env, self) 120 165 return self.__env 121 166 except Exception, e: 122 167 print 'Failed to open environment.', e … … 209 254 xrange(0, (1 + len(sep)) * cnum + sum(colw))]) 210 255 print 211 256 257 258 212 259 def print_doc(self, doc, decor=False): 213 260 if not doc: return 214 261 self.print_listing(['Command', 'Description'], doc, ' --', decor) … … 217 264 rows = self.db_query("SELECT name FROM component") 218 265 return [row[0] for row in rows] 219 266 220 def get_user_list(self):221 rows = self.db_query("SELECT DISTINCT username FROM permission")222 return [row[0] for row in rows]223 224 def get_wiki_list(self):225 rows = self.db_query('SELECT DISTINCT name FROM wiki')226 return [row[0] for row in rows]227 228 267 def get_dir_list(self, pathstr, justdirs=False): 229 268 dname = os.path.dirname(pathstr) 230 269 d = os.path.join(os.getcwd(), dname) … … 241 280 result = dlist 242 281 return result 243 282 244 def get_enum_list(self, type):245 rows = self.db_query("SELECT name FROM enum WHERE type='%s'" % type)246 return [row[0] for row in rows]247 283 248 def get_milestone_list(self):249 rows = self.db_query("SELECT name FROM milestone")250 return [row[0] for row in rows]251 252 284 def get_version_list(self): 253 285 rows = self.db_query("SELECT name FROM version") 254 286 return [row[0] for row in rows] … … 299 331 except AttributeError: 300 332 print "No documentation found for '%s'" % arg[0] 301 333 else: 302 docs = (self._help_about + self._help_help + 303 self._help_initenv + self._help_hotcopy + 304 self._help_resync + self._help_upgrade + 305 self._help_wiki + 306 # self._help_config + self._help_wiki + 307 self._help_permission + self._help_component + 308 self._help_ticket_type + self._help_priority + 309 self._help_severity + self._help_version + 310 self._help_milestone) 334 # Extract documentation from all _help_* members 335 docs = [] 336 doc_strings = [doc for doc in dir(self) if doc.startswith('_help_') and doc[6:] not in ('EOF', 'exit', 'quit')] 337 for doc in doc_strings: 338 docs.extend(getattr(self, doc)) 339 docs.sort(lambda a, b: cmp(a[0], b[0])) 340 311 341 print 'trac-admin - The Trac Administration Console %s' % trac.__version__ 312 342 if not self.interactive: 313 343 print … … 342 372 do_EOF = do_quit # Alias 343 373 344 374 345 # Component346 _help_component = [('component list', 'Show available components'),347 ('component add <name> <owner>', 'Add a new component'),348 ('component rename <name> <newname>',349 'Rename a component'),350 ('component remove <name>',351 'Remove/uninstall component'),352 ('component chown <name> <owner>',353 'Change component ownership')]354 355 def complete_component(self, text, line, begidx, endidx):356 if begidx in (16, 17):357 comp = self.get_component_list()358 elif begidx > 15 and line.startswith('component chown '):359 comp = self.get_user_list()360 else:361 comp = ['list', 'add', 'rename', 'remove', 'chown']362 return self.word_complete(text, comp)363 364 def do_component(self, line):365 arg = self.arg_tokenize(line)366 try:367 if arg[0] == 'list':368 self._do_component_list()369 elif arg[0] == 'add' and len(arg)==3:370 name = arg[1]371 owner = arg[2]372 self._do_component_add(name, owner)373 elif arg[0] == 'rename' and len(arg)==3:374 name = arg[1]375 newname = arg[2]376 self._do_component_rename(name, newname)377 elif arg[0] == 'remove' and len(arg)==2:378 name = arg[1]379 self._do_component_remove(name)380 elif arg[0] == 'chown' and len(arg)==3:381 name = arg[1]382 owner = arg[2]383 self._do_component_set_owner(name, owner)384 else:385 self.do_help ('component')386 except Exception, e:387 print 'Component %s failed:' % arg[0], e388 389 def _do_component_list(self):390 data = []391 for c in Component.select(self.env_open()):392 data.append((c.name, c.owner))393 self.print_listing(['Name', 'Owner'], data)394 395 def _do_component_add(self, name, owner):396 component = Component(self.env_open())397 component.name = name398 component.owner = owner399 component.insert()400 401 def _do_component_rename(self, name, newname):402 component = Component(self.env_open(), name)403 component.name = newname404 component.update()405 406 def _do_component_remove(self, name):407 component = Component(self.env_open(), name)408 component.delete()409 410 def _do_component_set_owner(self, name, owner):411 component = Component(self.env_open(), name)412 component.owner = owner413 component.update()414 415 416 ## Permission417 _help_permission = [('permission list [user]', 'List permission rules'),418 ('permission add <user> <action> [action] [...]',419 'Add a new permission rule'),420 ('permission remove <user> <action> [action] [...]',421 'Remove permission rule')]422 423 def complete_permission(self, text, line, begidx, endidx):424 argv = self.arg_tokenize(line)425 argc = len(argv)426 if line[-1] == ' ': # Space starts new argument427 argc += 1428 if argc == 2:429 comp = ['list', 'add', 'remove']430 elif argc >= 4:431 comp = perm.permissions + perm.meta_permissions.keys()432 comp.sort()433 return self.word_complete(text, comp)434 435 def do_permission(self, line):436 arg = self.arg_tokenize(line)437 try:438 if arg[0] == 'list':439 user = None440 if len(arg) > 1:441 user = arg[1]442 self._do_permission_list(user)443 elif arg[0] == 'add' and len(arg) >= 3:444 user = arg[1]445 for action in arg[2:]:446 self._do_permission_add(user, action)447 elif arg[0] == 'remove' and len(arg) >= 3:448 user = arg[1]449 for action in arg[2:]:450 self._do_permission_remove(user, action)451 else:452 self.do_help('permission')453 except Exception, e:454 print 'Permission %s failed:' % arg[0], e455 456 def _do_permission_list(self, user=None):457 if user:458 rows = self.db_query("SELECT username, action FROM permission "459 "WHERE username='%s' ORDER BY action" % user)460 else:461 rows = self.db_query("SELECT username, action FROM permission "462 "ORDER BY username, action")463 self.print_listing(['User', 'Action'], rows)464 print465 print 'Available actions:'466 actions = PermissionSystem(self.env_open()).get_actions()467 actions.sort()468 text = ', '.join(actions)469 print util.wrap(text, initial_indent=' ', subsequent_indent=' ',470 linesep='\n')471 print472 473 def _do_permission_add(self, user, action):474 if not action.islower() and not action.isupper():475 print 'Group names must be in lower case and actions in upper case'476 return477 self.db_update("INSERT INTO permission VALUES('%s', '%s')"478 % (user, action))479 480 def _do_permission_remove(self, user, action):481 sql = "DELETE FROM permission"482 clauses = []483 if action != '*':484 clauses.append("action='%s'" % action)485 if user != '*':486 clauses.append("username='%s'" % user)487 if clauses:488 sql += " WHERE " + " AND ".join(clauses)489 self.db_update(sql)490 491 492 375 ## Initenv 493 376 _help_initenv = [('initenv', 494 377 'Create and initialize a new environment interactively'), … … 589 472 print ' Installing default wiki pages' 590 473 cnx = self.__env.get_db_cnx() 591 474 cursor = cnx.cursor() 592 self. _do_wiki_load(default_dir('wiki'), cursor)475 self.do_wiki('load ' + default_dir('wiki')) 593 476 cnx.commit() 594 477 595 478 print ' Indexing repository' … … 650 533 651 534 print 'done.' 652 535 653 654 ## Wiki655 _help_wiki = [('wiki list', 'List wiki pages'),656 ('wiki remove <name>', 'Remove wiki page'),657 ('wiki export <page> [file]',658 'Export wiki page to file or stdout'),659 ('wiki import <page> [file]',660 'Import wiki page from file or stdin'),661 ('wiki dump <directory>',662 'Export all wiki pages to files named by title'),663 ('wiki load <directory>',664 'Import all wiki pages from directory'),665 ('wiki upgrade',666 'Upgrade default wiki pages to current version')]667 668 def complete_wiki(self, text, line, begidx, endidx):669 argv = self.arg_tokenize(line)670 argc = len(argv)671 if line[-1] == ' ': # Space starts new argument672 argc += 1673 if argc == 2:674 comp = ['list', 'remove', 'import', 'export', 'dump', 'load',675 'upgrade']676 else:677 if argv[1] in ('dump', 'load'):678 comp = self.get_dir_list(argv[-1], 1)679 elif argv[1] in ('export', 'import'):680 if argc == 3:681 comp = self.get_wiki_list()682 elif argc == 4:683 comp = self.get_dir_list(argv[-1])684 return self.word_complete(text, comp)685 686 def do_wiki(self, line):687 arg = self.arg_tokenize(line)688 try:689 if arg[0] == 'list':690 self._do_wiki_list()691 elif arg[0] == 'remove' and len(arg)==2:692 name = arg[1]693 self._do_wiki_remove(name)694 elif arg[0] == 'import' and len(arg) == 3:695 title = arg[1]696 file = arg[2]697 self._do_wiki_import(file, title)698 elif arg[0] == 'export' and len(arg) in [2,3]:699 page = arg[1]700 file = (len(arg) == 3 and arg[2]) or None701 self._do_wiki_export(page, file)702 elif arg[0] == 'dump' and len(arg) in [1,2]:703 dir = (len(arg) == 2 and arg[1]) or ''704 self._do_wiki_dump(dir)705 elif arg[0] == 'load' and len(arg) in [1,2]:706 dir = (len(arg) == 2 and arg[1]) or ''707 self._do_wiki_load(dir)708 elif arg[0] == 'upgrade' and len(arg) == 1:709 self._do_wiki_load(default_dir('wiki'),710 ignore=['WikiStart', 'checkwiki.py'])711 else:712 self.do_help ('wiki')713 except Exception, e:714 print 'Wiki %s failed:' % arg[0], e715 716 def _do_wiki_list(self):717 rows = self.db_query("SELECT name,max(version),time "718 "FROM wiki GROUP BY name ORDER BY name")719 self.print_listing(['Title', 'Edits', 'Modified'],720 [(r[0], r[1], self._format_datetime(r[2])) for r in rows])721 722 def _do_wiki_remove(self, name):723 cnx = self.db_open()724 cursor = cnx.cursor()725 cursor.execute('SELECT name FROM wiki WHERE name=%s', name)726 if not cursor.fetchone():727 raise Exception("No such wiki page '%s'" % name)728 cursor.execute("DELETE FROM wiki WHERE name=%s", (name,))729 730 def _do_wiki_import(self, filename, title, cursor=None):731 if not os.path.isfile(filename):732 print "%s is not a file" % filename733 return734 f = open(filename,'r')735 data = util.to_utf8(f.read())736 737 # Make sure we don't insert the exact same page twice738 rows = self.db_query("SELECT text FROM wiki WHERE name='%s' "739 "ORDER BY version DESC LIMIT 1" % title, cursor)740 old = list(rows)741 if old and data == old[0][0]:742 print ' %s already up to date.' % title743 return744 745 data = data.replace("'", "''") # Escape ' for safe SQL746 f.close()747 748 sql = ("INSERT INTO wiki(version,name,time,author,ipnr,text) "749 " SELECT 1+COALESCE(max(version),0),'%(title)s','%(time)s',"750 " '%(author)s','%(ipnr)s','%(text)s' FROM wiki "751 " WHERE name='%(title)s'"752 % {'title':title,753 'time':int(time.time()),754 'author':'trac',755 'ipnr':'127.0.0.1',756 'locked':'0',757 'text':data})758 self.db_update(sql, cursor)759 760 def _do_wiki_export(self, page, filename=''):761 data = self.db_query("SELECT text FROM wiki WHERE name='%s' "762 "ORDER BY version DESC LIMIT 1" % page)763 text = data.next()[0]764 if not filename:765 print text766 else:767 if os.path.isfile(filename):768 raise Exception("File '%s' exists" % filename)769 f = open(filename,'w')770 f.write(text)771 f.close()772 773 def _do_wiki_dump(self, dir):774 pages = self.get_wiki_list()775 for p in pages:776 dst = os.path.join(dir, urllib.quote(p, ''))777 print " %s => %s" % (p, dst)778 self._do_wiki_export(p, dst)779 780 def _do_wiki_load(self, dir, cursor=None, ignore=[]):781 for page in os.listdir(dir):782 if page in ignore:783 continue784 filename = os.path.join(dir, page)785 page = urllib.unquote(page)786 if os.path.isfile(filename):787 print " %s => %s" % (filename, page)788 self._do_wiki_import(filename, page, cursor)789 790 791 ## (Ticket) Type792 _help_ticket_type = [('ticket_type list', 'Show possible ticket types'),793 ('ticket_type add <value>', 'Add a ticket type'),794 ('ticket_type change <value> <newvalue>',795 'Change a ticket type'),796 ('ticket_type remove <value>', 'Remove a ticket type')]797 798 def complete_ticket_type (self, text, line, begidx, endidx):799 if begidx == 16:800 comp = self.get_enum_list ('ticket_type')801 elif begidx < 15:802 comp = ['list', 'add', 'change', 'remove']803 return self.word_complete(text, comp)804 805 def do_ticket_type(self, line):806 self._do_enum('ticket_type', line)807 808 ## (Ticket) Priority809 _help_priority = [('priority list', 'Show possible ticket priorities'),810 ('priority add <value>', 'Add a priority value option'),811 ('priority change <value> <newvalue>',812 'Change a priority value'),813 ('priority remove <value>', 'Remove priority value')]814 815 def complete_priority (self, text, line, begidx, endidx):816 if begidx == 16:817 comp = self.get_enum_list ('priority')818 elif begidx < 15:819 comp = ['list', 'add', 'change', 'remove']820 return self.word_complete(text, comp)821 822 def do_priority(self, line):823 self._do_enum('priority', line)824 825 ## (Ticket) Severity826 _help_severity = [('severity list', 'Show possible ticket severities'),827 ('severity add <value>', 'Add a severity value option'),828 ('severity change <value> <newvalue>',829 'Change a severity value'),830 ('severity remove <value>', 'Remove severity value')]831 832 def complete_severity (self, text, line, begidx, endidx):833 if begidx == 16:834 comp = self.get_enum_list ('severity')835 elif begidx < 15:
