Ticket #8751: transaction_rename_base.diff
| File transaction_rename_base.diff, 102.5 KB (added by shookie@…, 2 years ago) |
|---|
-
trac/attachment.py
diff --git a/trac/attachment.py b/trac/attachment.py index d084802..a3ed370 100644
a b from trac.admin import AdminCommandError, IAdminCommandProvider, PrefixList, \ 30 30 console_datetime_format, get_dir_list 31 31 from trac.config import BoolOption, IntOption 32 32 from trac.core import * 33 from trac.db.util import with_transaction 33 34 from trac.env import IEnvironmentSetupParticipant 34 35 from trac.mimeview import * 35 36 from trac.perm import PermissionError, IPermissionPolicy … … class Attachment(object): 170 171 171 172 def delete(self, db=None): 172 173 assert self.filename, 'Cannot delete non-existent attachment' 173 if not db:174 db = self.env.get_db_cnx()175 handle_ta = True176 else:177 handle_ta = False178 174 179 cursor = db.cursor() 180 cursor.execute("DELETE FROM attachment WHERE type=%s AND id=%s " 181 "AND filename=%s", (self.parent_realm, self.parent_id, 182 self.filename)) 183 if os.path.isfile(self.path): 184 try: 185 os.unlink(self.path) 186 except OSError, e: 187 self.env.log.error('Failed to delete attachment file %s: %s', 188 self.path, exception_to_unicode(e, traceback=True)) 189 if handle_ta: 190 db.rollback() 191 raise TracError(_('Could not delete attachment')) 175 @with_transaction(self.env, db) 176 def do_delete(db): 177 cursor = db.cursor() 178 cursor.execute("DELETE FROM attachment WHERE type=%s AND id=%s " 179 "AND filename=%s", 180 (self.parent_realm, self.parent_id, self.filename)) 181 if os.path.isfile(self.path): 182 try: 183 os.unlink(self.path) 184 except OSError, e: 185 self.env.log.error('Failed to delete attachment ' 186 'file %s: %s', 187 self.path, 188 exception_to_unicode(e, traceback=True)) 189 raise TracError(_('Could not delete attachment')) 192 190 193 191 self.env.log.info('Attachment removed: %s' % self.title) 194 if handle_ta:195 db.commit()196 192 197 193 for listener in AttachmentModule(self.env).change_listeners: 198 194 listener.attachment_deleted(self) … … class Attachment(object): 200 196 201 197 def insert(self, filename, fileobj, size, t=None, db=None): 202 198 # FIXME: `t` should probably be switched to `datetime` too 203 if not db:204 db = self.env.get_db_cnx()205 handle_ta = True206 else:207 handle_ta = False208 199 209 200 self.size = size and int(size) or 0 210 201 timestamp = int(t or time.time()) … … class Attachment(object): 228 219 basename = os.path.basename(path).encode('ascii') 229 220 filename = unicode_unquote(basename) 230 221 231 cursor = db.cursor() 232 cursor.execute("INSERT INTO attachment " 233 "VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", 234 (self.parent_realm, self.parent_id, filename, 235 self.size, timestamp, self.description, 236 self.author, self.ipnr)) 237 shutil.copyfileobj(fileobj, targetfile) 238 self.resource.id = self.filename = filename 239 240 self.env.log.info('New attachment: %s by %s', self.title, 241 self.author) 242 243 if handle_ta: 244 db.commit() 245 222 @with_transaction(self.env, db) 223 def do_insert(db): 224 cursor = db.cursor() 225 cursor.execute("INSERT INTO attachment " 226 "VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", 227 (self.parent_realm, self.parent_id, filename, 228 self.size, timestamp, self.description, 229 self.author, self.ipnr)) 230 shutil.copyfileobj(fileobj, targetfile) 231 self.resource.id = self.filename = filename 232 233 self.env.log.info('New attachment: %s by %s', self.title, 234 self.author) 235 finally: 246 236 targetfile.close() 247 237 248 for listener in AttachmentModule(self.env).change_listeners:249 listener.attachment_added(self)238 for listener in AttachmentModule(self.env).change_listeners: 239 listener.attachment_added(self) 250 240 251 finally:252 if not targetfile.closed:253 targetfile.close()254 241 255 242 @classmethod 256 243 def select(cls, env, parent_realm, parent_id, db=None): -
trac/cache.py
diff --git a/trac/cache.py b/trac/cache.py index 23b4245..d50974c 100644
a b except ImportError: 17 17 import dummy_threading as threading 18 18 19 19 from trac.core import Component 20 from trac.db.util import with_transaction 20 21 from trac.util.compat import partial 21 22 22 23 __all__ = ["CacheManager", "cached", "cached_value"] … … class CacheManager(Component): 189 190 self._lock.acquire() 190 191 try: 191 192 # Invalidate in other processes 192 handle_ta = db is None 193 if handle_ta: 194 db = self.env.get_db_cnx() 195 cursor = db.cursor() 196 193 197 194 # The row corresponding to the cache may not exist in the table 198 195 # yet. 199 196 # - If the row exists, the UPDATE increments the generation, the … … class CacheManager(Component): 201 198 # - If the row doesn't exist, the UPDATE does nothing, but starts 202 199 # a transaction. The SELECT then returns nothing, and we can 203 200 # safely INSERT a new row. 204 cursor.execute("UPDATE cache SET generation=generation+1 " 205 "WHERE id=%s", (id,)) 206 cursor.execute("SELECT generation FROM cache WHERE id=%s", (id,)) 207 if not cursor.fetchone(): 208 cursor.execute("INSERT INTO cache VALUES (%s, %s)", (id, 0)) 209 if handle_ta: 210 db.commit() 201 @with_transaction(self.env, db) 202 def do_invalidate(db): 203 cursor = db.cursor() 204 cursor.execute("UPDATE cache SET generation=generation+1 " 205 "WHERE id=%s", (id,)) 206 cursor.execute("SELECT generation FROM cache WHERE id=%s", 207 (id,)) 208 if not cursor.fetchone(): 209 cursor.execute("INSERT INTO cache VALUES (%s, %s)", (id, 0)) 211 210 212 211 # Invalidate in this process 213 212 self._cache.pop(id, None) -
trac/db/util.py
diff --git a/trac/db/util.py b/trac/db/util.py index 511e940..8bb9a5b 100644
a b 15 15 # 16 16 # Author: Christopher Lenz <cmlenz@gmx.de> 17 17 18 def with_transaction(env, db=None): 19 """Transaction decorator for simple use-once transactions. 20 Will be replaced by a context manager once python 2.4 support is dropped. 21 22 >>> def api_method(p1, p2): 23 >>> result[0] = value1 24 >>> @with_transaction(env, db) 25 >>> def implementation_method(db): 26 >>> # implementation 27 >>> result[0] = value2 28 """ 29 def transaction_wrapper(fn): 30 if db: 31 fn(db) 32 else: 33 dbtmp = env.get_db_cnx() 34 try: 35 fn(dbtmp) 36 dbtmp.commit() 37 except: 38 dbtmp.rollback() 39 raise 40 return transaction_wrapper 41 42 18 43 def sql_escape_percent(sql): 19 44 import re 20 45 return re.sub("'((?:[^']|(?:''))*)'", -
trac/env.py
diff --git a/trac/env.py b/trac/env.py index df08010..08646d2 100644
a b from trac.config import * 30 30 from trac.core import Component, ComponentManager, implements, Interface, \ 31 31 ExtensionPoint, TracError 32 32 from trac.db import DatabaseManager 33 from trac.db.util import with_transaction 33 34 from trac.util import copytree, create_file, get_pkginfo, makedirs 34 35 from trac.util.compat import any 35 36 from trac.util.text import exception_to_unicode, printerr, printout … … class Environment(Component, ComponentManager): 486 487 487 488 if backup: 488 489 self.backup(backup_dest) 489 for participant in upgraders: 490 participant.upgrade_environment(db) 491 db.commit() 490 491 @with_transaction(self.env) 492 def do_upgrade(db): 493 for participant in upgraders: 494 participant.upgrade_environment(db) 492 495 493 496 # Database schema may have changed, so close all connections 494 497 self.shutdown(except_logging=True) … … class EnvironmentSetup(Component): 520 523 521 524 def environment_created(self): 522 525 """Insert default data into the database.""" 523 db = self.env.get_db_cnx() 524 cursor = db.cursor() 525 for table, cols, vals in db_default.get_data(db): 526 cursor.executemany("INSERT INTO %s (%s) VALUES (%s)" % (table, 527 ','.join(cols), ','.join(['%s' for c in cols])), 528 vals) 529 db.commit() 526 @with_transaction(self.env) 527 def do_db_populate(db): 528 cursor = db.cursor() 529 for table, cols, vals in db_default.get_data(db): 530 cursor.executemany("INSERT INTO %s (%s) VALUES (%s)" 531 % (table, ','.join(cols), 532 ','.join(['%s' for c in cols])), 533 vals) 530 534 self._update_sample_config() 531 535 532 536 def environment_needs_upgrade(self, db): -
trac/perm.py
diff --git a/trac/perm.py b/trac/perm.py index 860d462..d43b591 100644
a b from time import time 21 21 from trac.admin import AdminCommandError, IAdminCommandProvider 22 22 from trac.config import ExtensionOption, OrderedExtensionsOption 23 23 from trac.core import * 24 from trac.db.util import with_transaction 24 25 from trac.resource import Resource, get_resource_name 25 26 from trac.util.text import print_table, printout, wrap 26 27 from trac.util.translation import _ … … class DefaultPermissionStore(Component): 221 222 222 223 def grant_permission(self, username, action): 223 224 """Grants a user the permission to perform the specified action.""" 224 db = self.env.get_db_cnx() 225 cursor = db.cursor() 226 cursor.execute("INSERT INTO permission VALUES (%s, %s)", 227 (username, action)) 228 self.log.info('Granted permission for %s to %s' % (action, username)) 229 db.commit() 225 @with_transaction(self.env) 226 def do_grant(db): 227 cursor = db.cursor() 228 cursor.execute("INSERT INTO permission VALUES (%s, %s)", 229 (username, action)) 230 self.log.info('Granted permission for %s to %s' 231 % (action, username)) 230 232 231 233 def revoke_permission(self, username, action): 232 234 """Revokes a users' permission to perform the specified action.""" 233 235 db = self.env.get_db_cnx() 234 cursor = db.cursor() 235 cursor.execute("DELETE FROM permission WHERE username=%s AND action=%s", 236 (username, action)) 237 self.log.info('Revoked permission for %s to %s' % (action, username)) 238 db.commit() 236 @with_transaction(self.env) 237 def do_revoke(db): 238 cursor = db.cursor() 239 cursor.execute("DELETE FROM permission WHERE username=%s " 240 "AND action=%s", 241 (username, action)) 242 self.log.info('Revoked permission for %s to %s' 243 % (action, username)) 239 244 240 245 241 246 class DefaultPermissionGroupProvider(Component): -
trac/ticket/admin.py
diff --git a/trac/ticket/admin.py b/trac/ticket/admin.py index ad0c9c3..4076fe6 100644
a b from datetime import datetime 15 15 16 16 from trac.admin import * 17 17 from trac.core import * 18 from trac.db.util import with_transaction 18 19 from trac.perm import PermissionSystem 19 20 from trac.resource import ResourceNotFound 20 21 from trac.ticket import model … … class ComponentAdminPanel(TicketAdminPanel): 125 126 raise TracError(_('No component selected')) 126 127 if not isinstance(sel, list): 127 128 sel = [sel] 128 db = self.env.get_db_cnx()129 for name in sel:130 comp = model.Component(self.env, name, db=db)131 comp.delete(db=db)132 db.commit()129 @with_transaction(self.env) 130 def do_remove(db): 131 for name in sel: 132 comp = model.Component(self.env, name, db=db) 133 comp.delete(db=db) 133 134 add_notice(req, _('The selected components have been ' 134 135 'removed.')) 135 136 req.redirect(req.href.admin(cat, page)) … … class ComponentAdminPanel(TicketAdminPanel): 215 216 component.insert() 216 217 217 218 def _do_rename(self, name, newname): 218 db = self.env.get_db_cnx()219 component = model.Component(self.env, name, db=db)220 component.name = newname221 component.update(db=db)222 db.commit()219 @with_transaction(self.env) 220 def do_rename(db): 221 component = model.Component(self.env, name, db=db) 222 component.name = newname 223 component.update(db=db) 223 224 224 225 def _do_remove(self, name): 225 db = self.env.get_db_cnx()226 component = model.Component(self.env, name, db=db)227 component.delete(db=db)228 db.commit()226 @with_transaction(self.env) 227 def do_remove(db): 228 component = model.Component(self.env, name, db=db) 229 component.delete(db=db) 229 230 230 231 def _do_chown(self, name, owner): 231 db = self.env.get_db_cnx()232 component = model.Component(self.env, name, db=db)233 component.owner = owner234 component.update(db=db)235 db.commit()232 @with_transaction(self.env) 233 def do_chown(db): 234 component = model.Component(self.env, name, db=db) 235 component.owner = owner 236 component.update(db=db) 236 237 237 238 238 239 class MilestoneAdminPanel(TicketAdminPanel): … … class MilestoneAdminPanel(TicketAdminPanel): 313 314 raise TracError(_('No milestone selected')) 314 315 if not isinstance(sel, list): 315 316 sel = [sel] 316 db = self.env.get_db_cnx()317 for name in sel:318 mil = model.Milestone(self.env, name, db=db)319 mil.delete(db=db, author=req.authname)320 db.commit()317 @with_transaction(self.env) 318 def do_remove(db): 319 for name in sel: 320 mil = model.Milestone(self.env, name, db=db) 321 mil.delete(db=db, author=req.authname) 321 322 add_notice(req, _('The selected milestones have been ' 322 323 'removed.')) 323 324 req.redirect(req.href.admin(cat, page)) … … class MilestoneAdminPanel(TicketAdminPanel): 407 408 milestone.insert() 408 409 409 410 def _do_rename(self, name, newname): 410 db = self.env.get_db_cnx()411 milestone = model.Milestone(self.env, name, db=db)412 milestone.name = newname413 milestone.update(db=db)414 db.commit()411 @with_transaction(self.env) 412 def do_rename(db): 413 milestone = model.Milestone(self.env, name, db=db) 414 milestone.name = newname 415 milestone.update(db=db) 415 416 416 417 def _do_due(self, name, due): 417 db = self.env.get_db_cnx()418 milestone = model.Milestone(self.env, name, db=db)419 milestone.due = due and parse_date(due)420 milestone.update(db=db)421 db.commit()418 @with_transaction(self.env) 419 def do_due(db): 420 milestone = model.Milestone(self.env, name, db=db) 421 milestone.due = due and parse_date(due) 422 milestone.update(db=db) 422 423 423 424 def _do_completed(self, name, completed): 424 db = self.env.get_db_cnx()425 milestone = model.Milestone(self.env, name, db=db)426 milestone.completed = completed and parse_date(completed)427 milestone.update(db=db)428 db.commit()425 @with_transaction(self.env) 426 def do_completed(db): 427 milestone = model.Milestone(self.env, name, db=db) 428 milestone.completed = completed and parse_date(completed) 429 milestone.update(db=db) 429 430 430 431 def _do_remove(self, name): 431 db = self.env.get_db_cnx()432 milestone = model.Milestone(self.env, name, db=db)433 milestone.delete(author=getuser(), db=db)434 db.commit()432 @with_transaction(self.env) 433 def do_remove(db): 434 milestone = model.Milestone(self.env, name, db=db) 435 milestone.delete(author=getuser(), db=db) 435 436 436 437 437 438 class VersionAdminPanel(TicketAdminPanel): … … class VersionAdminPanel(TicketAdminPanel): 493 494 raise TracError(_('No version selected')) 494 495 if not isinstance(sel, list): 495 496 sel = [sel] 496 db = self.env.get_db_cnx()497 for name in sel:498 ver = model.Version(self.env, name, db=db)499 ver.delete(db=db)500 db.commit()497 @with_transaction(self.env) 498 def do_remove(db): 499 for name in sel: 500 ver = model.Version(self.env, name, db=db) 501 ver.delete(db=db) 501 502 add_notice(req, _('The selected versions have been ' 502 503 'removed.')) 503 504 req.redirect(req.href.admin(cat, page)) … … class VersionAdminPanel(TicketAdminPanel): 566 567 version.insert() 567 568 568 569 def _do_rename(self, name, newname): 569 db = self.env.get_db_cnx()570 version = model.Version(self.env, name, db=db)571 version.name = newname572 version.update(db=db)573 db.commit()570 @with_transaction(self.env) 571 def do_rename(db): 572 version = model.Version(self.env, name, db=db) 573 version.name = newname 574 version.update(db=db) 574 575 575 576 def _do_time(self, name, time): 576 db = self.env.get_db_cnx()577 version = model.Version(self.env, name, db=db)578 version.time = time and parse_date(time)579 version.update(db=db)580 db.commit()577 @with_transaction(self.env) 578 def do_time(db): 579 version = model.Version(self.env, name, db=db) 580 version.time = time and parse_date(time) 581 version.update(db=db) 581 582 582 583 def _do_remove(self, name): 583 db = self.env.get_db_cnx()584 version = model.Version(self.env, name, db=db)585 version.delete(db=db)586 db.commit()584 @with_transaction(self.env) 585 def do_remove(db): 586 version = model.Version(self.env, name, db=db) 587 version.delete(db=db) 587 588 588 589 589 590 class AbstractEnumAdminPanel(TicketAdminPanel): … … class AbstractEnumAdminPanel(TicketAdminPanel): 643 644 raise TracError(_('No %s selected') % self._type) 644 645 if not isinstance(sel, list): 645 646 sel = [sel] 646 db = self.env.get_db_cnx()647 for name in sel:648 enum = self._enum_cls(self.env, name, db=db)649 enum.delete(db=db)650 db.commit()647 @with_transaction(self.env) 648 def do_remove(db): 649 for name in sel: 650 enum = self._enum_cls(self.env, name, db=db) 651 enum.delete(db=db) 651 652 add_notice(req, _('The selected %(fields)s have been ' 652 653 'removed.', 653 654 fields=self._label[1].lower())) 654 655 req.redirect(req.href.admin(cat, page)) 655 656 656 # App y changes657 # Apply changes 657 658 elif req.args.get('apply'): 658 changed = False659 changed = [False] 659 660 660 661 # Set default value 661 662 name = req.args.get('default') … … class AbstractEnumAdminPanel(TicketAdminPanel): 666 667 name) 667 668 try: 668 669 self.config.save() 669 changed = True670 changed[0] = True 670 671 except Exception, e: 671 672 self.log.error('Error writing to trac.ini: %s', 672 673 exception_to_unicode(e)) … … class AbstractEnumAdminPanel(TicketAdminPanel): 684 685 values = dict([(val, True) for val in order.values()]) 685 686 if len(order) != len(values): 686 687 raise TracError(_('Order numbers must be unique')) 687 db = self.env.get_db_cnx()688 for enum in self._enum_cls.select(self.env, db=db):689 new_value = order[enum.value]690 if new_value != enum.value:691 enum.value = new_value692 enum.update(db=db)693 changed = True694 db.commit()695 696 if changed :688 @with_transaction(self.env) 689 def do_change(db): 690 for enum in self._enum_cls.select(self.env, db=db): 691 new_value = order[enum.value] 692 if new_value != enum.value: 693 enum.value = new_value 694 enum.update(db=db) 695 changed[0] = True 696 697 if changed[0]: 697 698 add_notice(req, _('Your changes have been saved.')) 698 699 req.redirect(req.href.admin(cat, page)) 699 700 … … class AbstractEnumAdminPanel(TicketAdminPanel): 753 754 enum.insert() 754 755 755 756 def _do_change(self, name, newname): 756 db = self.env.get_db_cnx()757 enum = self._enum_cls(self.env, name, db=db)758 enum.name = newname759 enum.update(db=db)760 db.commit()757 @with_transaction(self.env) 758 def do_change(db): 759 enum = self._enum_cls(self.env, name, db=db) 760 enum.name = newname 761 enum.update(db=db) 761 762 762 763 def _do_remove(self, value): 763 db = self.env.get_db_cnx()764 enum = self._enum_cls(self.env, value, db=db)765 enum.delete(db=db)766 db.commit()764 @with_transaction(self.env) 765 def do_remove(db): 766 enum = self._enum_cls(self.env, value, db=db) 767 enum.delete(db=db) 767 768 768 769 def _do_order(self, name, up_down): 769 770 if up_down not in ('up', 'down'): … … class AbstractEnumAdminPanel(TicketAdminPanel): 779 780 break 780 781 else: 781 782 return 782 enum1.update(db=db) 783 enum2.update(db=db) 784 db.commit() 783 @with_transaction(self.env) 784 def do_order(db): 785 enum1.update(db=db) 786 enum2.update(db=db) 787 785 788 786 789 787 790 class PriorityAdminPanel(AbstractEnumAdminPanel): … … class TicketAdmin(Component): 834 837 number = int(number) 835 838 except ValueError: 836 839 raise AdminCommandError(_('<number> must be a number')) 837 db = self.env.get_db_cnx()838 ticket = model.Ticket(self.env, number, db=db)839 ticket.delete(db=db)840 db.commit()840 @with_transaction(self.env) 841 def do_remove(db): 842 ticket = model.Ticket(self.env, number, db=db) 843 ticket.delete(db=db) 841 844 printout(_('Ticket %(num)s and all associated data removed.', 842 845 num=number)) -
trac/ticket/model.py
diff --git a/trac/ticket/model.py b/trac/ticket/model.py index 5b91fd6..7ec802e 100644
a b from datetime import date, datetime 22 22 23 23 from trac.attachment import Attachment 24 24 from trac.core import TracError 25 from trac.db.util import with_transaction 25 26 from trac.resource import Resource, ResourceNotFound 26 27 from trac.ticket.api import TicketSystem 27 28 from trac.util import embedded_numbers, partition … … class Ticket(object): 65 66 def _get_db(self, db): 66 67 return db or self.env.get_db_cnx() 67 68 68 def _get_db_for_write(self, db):69 if db:70 return (db, False)71 else:72 return (self.env.get_db_cnx(), True)73 74 69 exists = property(fget=lambda self: self.id is not None) 75 70 76 71 def _init_defaults(self, db=None): … … class Ticket(object): 178 173 def insert(self, when=None, db=None): 179 174 """Add ticket to database""" 180 175 assert not self.exists, 'Cannot insert an existing ticket' 181 db, handle_ta = self._get_db_for_write(db)182 176 183 177 # Add a timestamp 184 178 if when is None: 185 179 when = datetime.now(utc) 186 180 self.values['time'] = self.values['changetime'] = when 187 181 188 cursor = db.cursor()189 190 182 # The owner field defaults to the component owner 191 183 if self.values.get('component') and not self.values.get('owner'): 192 184 try: … … class Ticket(object): 213 205 custom_fields.append(fname) 214 206 else: 215 207 std_fields.append(fname) 216 cursor.execute("INSERT INTO ticket (%s) VALUES (%s)"217 % (','.join(std_fields),218 ','.join(['%s'] * len(std_fields))),219 [values[name] for name in std_fields])220 tkt_id = db.get_last_id(cursor, 'ticket')221 222 # Insert custom fields223 if custom_fields:224 cursor.executemany("INSERT INTO ticket_custom (ticket,name,value) "225 "VALUES (%s,%s,%s)", [(tkt_id, name, self[name])226 for name in custom_fields])227 if handle_ta:228 db.commit()229 208 230 self.id = tkt_id 231 self.resource = self.resource(id=tkt_id) 209 @with_transaction(self.env, db) 210 def do_insert(db): 211 cursor = db.cursor() 212 cursor.execute("INSERT INTO ticket (%s) VALUES (%s)" 213 % (','.join(std_fields), 214 ','.join(['%s'] * len(std_fields))), 215 [values[name] for name in std_fields]) 216 self.id = db.get_last_id(cursor, 'ticket') 217 218 # Insert custom fields 219 if custom_fields: 220 cursor.executemany("INSERT INTO ticket_custom " 221 "(ticket,name,value) VALUES (%s,%s,%s)", 222 [(self.id, name, self[name]) 223 for name in custom_fields]) 224 225 self.resource = self.resource(id=self.id) 232 226 self._old = {} 233 227 234 228 for listener in TicketSystem(self.env).change_listeners: … … class Ticket(object): 247 241 if not self._old and not comment: 248 242 return False # Not modified 249 243 250 db, handle_ta = self._get_db_for_write(db)251 cursor = db.cursor()252 244 if when is None: 253 245 when = datetime.now(utc) 254 246 when_ts = to_timestamp(when) 255 247 256 248 if 'component' in self.values: 257 # If the component is changed on a 'new' ticket then owner field258 # is updated accordingly. (#623).249 # If the component is changed on a 'new' ticket 250 # then owner field is updated accordingly. (#623). 259 251 if self.values.get('status') == 'new' \ 260 252 and 'component' in self._old \ 261 253 and 'owner' not in self._old: 262 254 try: 263 old_comp = Component(self.env, self._old['component'] , db)255 old_comp = Component(self.env, self._old['component']) 264 256 old_owner = old_comp.owner or '' 265 257 current_owner = self.values.get('owner') or '' 266 258 if old_owner == current_owner: 267 new_comp = Component(self.env, self['component'] , db)259 new_comp = Component(self.env, self['component']) 268 260 if new_comp.owner: 269 261 self['owner'] = new_comp.owner 270 262 except TracError: … … class Ticket(object): 279 271 if cc not in cclist: 280 272 cclist.append(cc) 281 273 self.values['cc'] = ', '.join(cclist) 282 283 # find cnum if it isn't provided 284 if not cnum: 285 num = 0 286 cursor.execute(""" 287 SELECT DISTINCT tc1.time,COALESCE(tc2.oldvalue,'') 288 FROM ticket_change AS tc1 289 LEFT OUTER JOIN 290 (SELECT time,oldvalue FROM ticket_change 291 WHERE field='comment') AS tc2 292 ON (tc1.time = tc2.time) 293 WHERE ticket=%s ORDER BY tc1.time DESC 294 """, (self.id,)) 295 for ts, old in cursor: 296 # Use oldvalue if available, else count edits 297 try: 298 num += int(old.rsplit('.', 1)[-1]) 299 break 300 except ValueError: 301 num += 1 302 cnum = str(num + 1) 303 304 # store fields 305 custom_fields = [f['name'] for f in self.fields if f.get('custom')] 306 for name in self._old.keys(): 307 if name in custom_fields: 308 cursor.execute("SELECT * FROM ticket_custom " 309 "WHERE ticket=%s and name=%s", (self.id, name)) 310 if cursor.fetchone(): 311 cursor.execute("UPDATE ticket_custom SET value=%s " 312 "WHERE ticket=%s AND name=%s", 313 (self[name], self.id, name)) 274 275 @with_transaction(self.env, db) 276 def do_save(db): 277 cursor = db.cursor() 278 279 # find cnum if it isn't provided 280 comment_num = cnum 281 if not comment_num: 282 num = 0 283 cursor.execute(""" 284 SELECT DISTINCT tc1.time,COALESCE(tc2.oldvalue,'') 285 FROM ticket_change AS tc1 286 LEFT OUTER JOIN 287 (SELECT time,oldvalue FROM ticket_change 288 WHERE field='comment') AS tc2 289 ON (tc1.time = tc2.time) 290 WHERE ticket=%s ORDER BY tc1.time DESC 291 """, (self.id,)) 292 for ts, old in cursor: 293 # Use oldvalue if available, else count edits 294 try: 295 num += int(old.rsplit('.', 1)[-1]) 296 break 297 except ValueError: 298 num += 1 299 comment_num = str(num + 1) 300 301 # store fields 302 custom_fields = [f['name'] for f in self.fields if f.get('custom')] 303 304 for name in self._old.keys(): 305 if name in custom_fields: 306 cursor.execute(""" 307 SELECT * FROM ticket_custom 308 WHERE ticket=%s and name=%s 309 """, (self.id, name)) 310 if cursor.fetchone(): 311 cursor.execute(""" 312 UPDATE ticket_custom SET value=%s 313 WHERE ticket=%s AND name=%s 314 """, (self[name], self.id, name)) 315 else: 316 cursor.execute(""" 317 INSERT INTO ticket_custom (ticket,name,value) 318 VALUES(%s,%s,%s) 319 """, (self.id, name, self[name])) 314 320 else: 315 cursor.execute("INSERT INTO ticket_custom (ticket,name," 316 "value) VALUES(%s,%s,%s)", 317 (self.id, name, self[name])) 318 else: 319 cursor.execute("UPDATE ticket SET %s=%%s WHERE id=%%s" % name, 320 (self[name], self.id)) 321 cursor.execute("INSERT INTO ticket_change " 322 "(ticket,time,author,field,oldvalue,newvalue) " 323 "VALUES (%s, %s, %s, %s, %s, %s)", 324 (self.id, when_ts, author, name, self._old[name], 325 self[name])) 326 327 # always save comment, even if empty (numbering support for timeline) 328 cursor.execute("INSERT INTO ticket_change " 329 "(ticket,time,author,field,oldvalue,newvalue) " 330 "VALUES (%s,%s,%s,'comment',%s,%s)", 331 (self.id, when_ts, author, cnum, comment)) 332 333 cursor.execute("UPDATE ticket SET changetime=%s WHERE id=%s", 334 (when_ts, self.id)) 321 cursor.execute("UPDATE ticket SET %s=%%s WHERE id=%%s" 322 % name, (self[name], self.id)) 323 cursor.execute(""" 324 INSERT INTO ticket_change 325 (ticket,time,author,field,oldvalue,newvalue) 326 VALUES (%s, %s, %s, %s, %s, %s) 327 """, (self.id, when_ts, author, name, self._old[name], 328 self[name])) 329 330 # always save comment, even if empty (numbering support for timeline) 331 cursor.execute(""" 332 INSERT INTO ticket_change 333 (ticket,time,author,field,oldvalue,newvalue) 334 VALUES (%s,%s,%s,'comment',%s,%s) 335 """, (self.id, when_ts, author, comment_num, comment)) 336 337 cursor.execute("UPDATE ticket SET changetime=%s WHERE id=%s", 338 (when_ts, self.id)) 335 339 336 if handle_ta:337 db.commit()338 340 old_values = self._old 339 341 self._old = {} 340 342 self.values['changetime'] = when … … class Ticket(object): 387 389 return log 388 390 389 391 def delete(self, db=None): 390 db, handle_ta = self._get_db_for_write(db)391 Attachment.delete_all(self.env, 'ticket', self.id, db)392 cursor = db.cursor()393 cursor.execute("DELETE FROM ticket WHERE id=%s", (self.id,))394 cursor.execute("DELETE FROM ticket_change WHERE ticket=%s", (self.id,))395 cursor.execute("DELETE FROM ticket_custom WHERE ticket=%s", (self.id,))396 397 if handle_ta:398 db.commit()392 @with_transaction(self.env, db) 393 def do_delete(db): 394 Attachment.delete_all(self.env, 'ticket', self.id, db) 395 cursor = db.cursor() 396 cursor.execute("DELETE FROM ticket WHERE id=%s", (self.id,)) 397 cursor.execute("DELETE FROM ticket_change WHERE ticket=%s", 398 (self.id,)) 399 cursor.execute("DELETE FROM ticket_custom WHERE ticket=%s", 400 (self.id,)) 399 401 400 402 for listener in TicketSystem(self.env).change_listeners: 401 403 listener.ticket_deleted(self) … … class Ticket(object): 426 428 if when is None: 427 429 when = datetime.now(utc) 428 430 when_ts = to_timestamp(when) 429 430 db, handle_ta = self._get_db_for_write(db) 431 cursor = db.cursor() 432 433 # Find the current value of the comment 434 cursor.execute("SELECT newvalue FROM ticket_change " 435 "WHERE ticket=%s AND time=%s AND field='comment'", 436 (self.id, ts)) 437 old_comment = False 438 for old_comment, in cursor: 439 break 440 if comment == (old_comment or ''): 441 return 442 443 # Comment history is stored in fields named "_comment%d" 444 # Find the next edit number 445 cursor.execute("SELECT field FROM ticket_change " 446 "WHERE ticket=%%s AND time=%%s AND field %s" 447 % db.like(), 448 (self.id, ts, db.like_escape('_comment') + '%')) 449 fields = list(cursor) 450 rev = fields and max(int(field[8:]) for field, in fields) + 1 or 0 451 cursor.execute("INSERT INTO ticket_change " 452 "(ticket,time,author,field,oldvalue,newvalue) " 453 "VALUES (%s,%s,%s,%s,%s,%s)", 454 (self.id, ts, author, '_comment%d' % rev, 455 old_comment or '', str(when_ts))) 456 if old_comment is False: 457 # There was no comment field, add one and find the original author 458 # in one of the other changed fields 459 cursor.execute("SELECT author FROM ticket_change " 460 "WHERE ticket=%%s AND time=%%s AND NOT field %s " 461 "LIMIT 1" % db.like(), 462 (self.id, ts, db.like_escape('_') + '%')) 463 old_author = None 464 for old_author, in cursor: 431 432 @with_transaction(self.env, db) 433 def do_save(db): 434 cursor = db.cursor() 435 # Find the current value of the comment 436 cursor.execute("SELECT newvalue FROM ticket_change " 437 "WHERE ticket=%s AND time=%s AND field='comment'", 438 (self.id, ts)) 439 old_comment = False 440 for old_comment, in cursor: 465 441 break 442 if comment == (old_comment or ''): 443 return 444 445 # Comment history is stored in fields named "_comment%d" 446 # Find the next edit number 447 cursor.execute("SELECT field FROM ticket_change " 448 "WHERE ticket=%%s AND time=%%s AND field %s" 449 % db.like(), 450 (self.id, ts, db.like_escape('_comment') + '%')) 451 fields = list(cursor) 452 rev = fields and max(int(field[8:]) for field, in fields) + 1 or 0 466 453 cursor.execute("INSERT INTO ticket_change " 467 " (ticket,time,author,field,oldvalue,newvalue) " 468 "VALUES (%s,%s,%s,'comment','',%s)", 469 (self.id, ts, old_author, comment)) 470 else: 471 cursor.execute("UPDATE ticket_change SET newvalue=%s " 472 "WHERE ticket=%s AND time=%s AND field='comment'", 473 (comment, self.id, ts)) 474 if handle_ta: 475 db.commit() 454 "(ticket,time,author,field,oldvalue,newvalue) " 455 "VALUES (%s,%s,%s,%s,%s,%s)", 456 (self.id, ts, author, '_comment%d' % rev, 457 old_comment or '', str(when_ts))) 458 if old_comment is False: 459 # There was no comment field, add one, find the original author 460 # in one of the other changed fields 461 cursor.execute("SELECT author FROM ticket_change " 462 "WHERE ticket=%%s AND time=%%s AND NOT field %s" 463 " LIMIT 1" % db.like(), 464 (self.id, ts, db.like_escape('_') + '%')) 465 old_author = None 466 for old_author, in cursor: 467 break 468 cursor.execute("INSERT INTO ticket_change " 469 " (ticket,time,author,field,oldvalue,newvalue) " 470 "VALUES (%s,%s,%s,'comment','',%s)", 471 (self.id, ts, old_author, comment)) 472 else: 473 cursor.execute("UPDATE ticket_change SET newvalue=%s " 474 "WHERE ticket=%s AND time=%s AND " 475 "field='comment'", 476 (comment, self.id, ts)) 476 477 477 478 def get_comment_history(self, cnum, db=None): 478 479 db = self._get_db(db) … … class AbstractEnum(object): 583 584 584 585 def delete(self, db=None): 585 586 assert self.exists, 'Cannot delete non-existent %s' % self.type 586 if not db:587 db = self.env.get_db_cnx()588 handle_ta = True589 else:590 handle_ta = False591 587 592 cursor = db.cursor() 593 self.env.log.info('Deleting %s %s' % (self.type, self.name)) 594 cursor.execute("DELETE FROM enum WHERE type=%s AND value=%s", 595 (self.type, self._old_value)) 596 # Re-order any enums that have higher value than deleted (close gap) 597 for enum in list(self.select(self.env)): 598 try: 599 if int(enum.value) > int(self._old_value): 600 enum.value = unicode(int(enum.value) - 1) 601 enum.update(db=db) 602 except ValueError: 603 pass # Ignore cast error for this non-essential operation 604 TicketSystem(self.env).reset_ticket_fields(db) 605 606 if handle_ta: 607 db.commit() 588 @with_transaction(self.env, db) 589 def do_delete(db): 590 cursor = db.cursor() 591 self.env.log.info('Deleting %s %s' % (self.type, self.name)) 592 cursor.execute("DELETE FROM enum WHERE type=%s AND value=%s", 593 (self.type, self._old_value)) 594 # Re-order any enums that have higher value than deleted (close gap) 595 for enum in list(self.select(self.env, db)): 596 try: 597 if int(enum.value) > int(self._old_value): 598 enum.value = unicode(int(enum.value) - 1) 599 enum.update(db=db) 600 except ValueError: 601 pass # Ignore cast error for this non-essential operation 602 TicketSystem(self.env).reset_ticket_fields(db) 608 603 self.value = self._old_value = None 609 604 self.name = self._old_name = None 610 605 … … class AbstractEnum(object): 613 608 self.name = simplify_whitespace(self.name) 614 609 if not self.name: 615 610 raise TracError(_('Invalid %(type)s name.', type=self.type)) 616 if not db:617 db = self.env.get_db_cnx()618 handle_ta = True619 else:620 handle_ta = False621 611 622 cursor = db.cursor() 623 self.env.log.debug("Creating new %s '%s'" % (self.type, self.name)) 624 if not self.value: 625 cursor.execute(("SELECT COALESCE(MAX(%s),0) FROM enum " 626 "WHERE type=%%s") % db.cast('value', 'int'), 627 (self.type,)) 628 self.value = int(float(cursor.fetchone()[0])) + 1 629 cursor.execute("INSERT INTO enum (type,name,value) VALUES (%s,%s,%s)", 630 (self.type, self.name, self.value)) 631 TicketSystem(self.env).reset_ticket_fields(db) 632 633 if handle_ta: 634 db.commit() 612 @with_transaction(self.env, db) 613 def do_insert(db): 614 cursor = db.cursor() 615 self.env.log.debug("Creating new %s '%s'" % (self.type, self.name)) 616 if not self.value: 617 cursor.execute(("SELECT COALESCE(MAX(%s),0) FROM enum " 618 "WHERE type=%%s") % db.cast('value', 'int'), 619 (self.type,)) 620 self.value = int(float(cursor.fetchone()[0])) + 1 621 cursor.execute("INSERT INTO enum (type,name,value) " 622 "VALUES (%s,%s,%s)", 623 (self.type, self.name, self.value)) 624 TicketSystem(self.env).reset_ticket_fields(db) 625 635 626 self._old_name = self.name 636 627 self._old_value = self.value 637 628 … … class AbstractEnum(object): 640 631 self.name = simplify_whitespace(self.name) 641 632 if not self.name: 642 633 raise TracError(_('Invalid %(type)s name.', type=self.type)) 643 if not db:644 db = self.env.get_db_cnx()645 handle_ta = True646 else:647 handle_ta = False648 634 649 cursor = db.cursor()650 self.env.log.info('Updating %s "%s"' % (self.type, self.name))651 cursor.execute("UPDATE enum SET name=%s,value=%s "652 "WHERE type=%s AND name=%s",653 (self.name, self.value, self.type, self._old_name))654 if self.name != self._old_name:655 # Update tickets656 cursor.execute("UPDATE ticket SET %s=%%s WHERE %s=%%s" %657 (self.ticket_col, self.ticket_col),658 (self.name, self._old_name))659 TicketSystem(self.env).reset_ticket_fields(db)660 661 if handle_ta:662 db.commit() 635 @with_transaction(self.env, db) 636 def do_update(db): 637 cursor = db.cursor() 638 self.env.log.info('Updating %s "%s"' % (self.type, self.name)) 639 cursor.execute("UPDATE enum SET name=%s,value=%s " 640 "WHERE type=%s AND name=%s", 641 (self.name, self.value, self.type, self._old_name)) 642 if self.name != self._old_name: 643 # Update tickets 644 cursor.execute("UPDATE ticket SET %s=%%s WHERE %s=%%s" % 645 (self.ticket_col, self.ticket_col), 646 (self.name, self._old_name)) 647 TicketSystem(self.env).reset_ticket_fields(db) 648 663 649 self._old_name = self.name 664 650 self._old_value = self.value 665 651 … … class Component(object): 734 720 735 721 def delete(self, db=None): 736 722 assert self.exists, 'Cannot delete non-existent component' 737 if not db:738 db = self.env.get_db_cnx()739 handle_ta = True740 else:741 handle_ta = False742 723 743 cursor = db.cursor() 744 self.env.log.info('Deleting component %s' % self.name) 745 cursor.execute("DELETE FROM component WHERE name=%s", (self.name,)) 746 self.name = self._old_name = None 747 TicketSystem(self.env).reset_ticket_fields(db) 748 749 if handle_ta: 750 db.commit() 724 @with_transaction(self.env, db) 725 def do_delete(db): 726 cursor = db.cursor() 727 self.env.log.info('Deleting component %s' % self.name) 728 cursor.execute("DELETE FROM component WHERE name=%s", (self.name,)) 729 self.name = self._old_name = None 730 TicketSystem(self.env).reset_ticket_fields(db) 751 731 752 732 def insert(self, db=None): 753 733 assert not self.exists, 'Cannot insert existing component' 754 734 self.name = simplify_whitespace(self.name) 755 735 if not self.name: 756 736 raise TracError(_('Invalid component name.')) 757 if not db:758 db = self.env.get_db_cnx()759 handle_ta = True760 else:761 handle_ta = False762 737 763 cursor = db.cursor() 764 self.env.log.debug("Creating new component '%s'" % self.name) 765 cursor.execute("INSERT INTO component (name,owner,description) " 766 "VALUES (%s,%s,%s)", 767 (self.name, self.owner, self.description)) 768 self._old_name = self.name 769 TicketSystem(self.env).reset_ticket_fields(db) 770 771 if handle_ta: 772 db.commit() 738 @with_transaction(self.env, db) 739 def do_insert(db): 740 cursor = db.cursor() 741 self.env.log.debug("Creating new component '%s'" % self.name) 742 cursor.execute("INSERT INTO component (name,owner,description) " 743 "VALUES (%s,%s,%s)", 744 (self.name, self.owner, self.description)) 745 self._old_name = self.name 746 TicketSystem(self.env).reset_ticket_fields(db) 773 747 774 748 def update(self, db=None): 775 749 assert self.exists, 'Cannot update non-existent component' 776 750 self.name = simplify_whitespace(self.name) 777 751 if not self.name: 778 752 raise TracError(_('Invalid component name.')) 779 if not db:780 db = self.env.get_db_cnx()781 handle_ta = True782 else:783 handle_ta = False784 753 785 cursor = db.cursor()786 self.env.log.info('Updating component "%s"' % self.name)787 cursor.execute("UPDATE component SET name=%s,owner=%s,description=%s "788 "WHERE name=%s",789 (self.name, self.owner, self.description,790 self._old_name))791 if self.name != self._old_name:792 # Update tickets793 cursor.execute("UPDATE ticket SET component=%s WHERE component=%s",794 (self.name, self._old_name))795 self._old_name = self.name796 TicketSystem(self.env).reset_ticket_fields(db)797 798 if handle_ta:799 db.commit()754 @with_transaction(self.env, db) 755 def do_update(db): 756 cursor = db.cursor() 757 self.env.log.info('Updating component "%s"' % self.name) 758 cursor.execute("UPDATE component SET name=%s,owner=%s," 759 "description=%s WHERE name=%s", 760 (self.name, self.owner, self.description, 761 self._old_name)) 762 if self.name != self._old_name: 763 # Update tickets 764 cursor.execute("UPDATE ticket SET component=%s " 765 "WHERE component=%s", 766 (self.name, self._old_name)) 767 self._old_name = self.name 768 TicketSystem(self.env).reset_ticket_fields(db) 800 769 801 770 @classmethod 802 771 def select(cls, env, db=None): … … class Milestone(object): 862 831 'description': self.description} 863 832 864 833 def delete(self, retarget_to=None, author=None, db=None): 865 if not db: 866 db = self.env.get_db_cnx() 867 handle_ta = True 868 else: 869 handle_ta = False 870 871 cursor = db.cursor() 872 self.env.log.info('Deleting milestone %s' % self.name) 873 cursor.execute("DELETE FROM milestone WHERE name=%s", (self.name,)) 874 875 # Retarget/reset tickets associated with this milestone 876 now = datetime.now(utc) 877 cursor.execute("SELECT id FROM ticket WHERE milestone=%s", (self.name,)) 878 tkt_ids = [int(row[0]) for row in cursor] 879 for tkt_id in tkt_ids: 880 ticket = Ticket(self.env, tkt_id, db) 881 ticket['milestone'] = retarget_to 882 ticket.save_changes(author, 'Milestone %s deleted' % self.name, 883 now, db=db) 884 self._old['name'] = None 885 TicketSystem(self.env).reset_ticket_fields(db) 886 887 if handle_ta: 888 db.commit() 834 @with_transaction(self.env, db) 835 def do_delete(db): 836 cursor = db.cursor() 837 self.env.log.info('Deleting milestone %s' % self.name) 838 cursor.execute("DELETE FROM milestone WHERE name=%s", (self.name,)) 839 840 # Retarget/reset tickets associated with this milestone 841 now = datetime.now(utc) 842 cursor.execute("SELECT id FROM ticket WHERE milestone=%s", 843 (self.name,)) 844 tkt_ids = [int(row[0]) for row in cursor] 845 for tkt_id in tkt_ids: 846 ticket = Ticket(self.env, tkt_id, db) 847 ticket['milestone'] = retarget_to 848 ticket.save_changes(author, 'Milestone %s deleted' % self.name, 849 now, db=db) 850 self._old['name'] = None 851 TicketSystem(self.env).reset_ticket_fields(db) 889 852 890 853 for listener in TicketSystem(self.env).milestone_change_listeners: 891 854 listener.milestone_deleted(self) … … class Milestone(object): 894 857 self.name = simplify_whitespace(self.name) 895 858 if not self.name: 896 859 raise TracError(_('Invalid milestone name.')) 897 if not db:898 db = self.env.get_db_cnx()899 handle_ta = True900 else:901 handle_ta = False902 860 903 cursor = db.cursor()904 self.env.log.debug("Creating new milestone '%s'" % self.name)905 cursor.execute("INSERT INTO milestone (name,due,completed,description) "906 "VALUES (%s,%s,%s,%s)",907 (self.name, to_timestamp(self.due), to_timestamp(self.completed),908 self.description))909 self._to_old()910 TicketSystem(self.env).reset_ticket_fields(db)911 912 if handle_ta:913 db.commit()861 @with_transaction(self.env, db) 862 def do_insert(db): 863 cursor = db.cursor() 864 self.env.log.debug("Creating new milestone '%s'" % self.name) 865 cursor.execute("INSERT INTO milestone " 866 "(name,due,completed,description) " 867 "VALUES (%s,%s,%s,%s)", 868 (self.name, to_timestamp(self.due), 869 to_timestamp(self.completed), self.description)) 870 self._to_old() 871 TicketSystem(self.env).reset_ticket_fields(db) 914 872 915 873 for listener in TicketSystem(self.env).milestone_change_listeners: 916 874 listener.milestone_created(self) … … class Milestone(object): 919 877 self.name = simplify_whitespace(self.name) 920 878 if not self.name: 921 879 raise TracError(_('Invalid milestone name.')) 922 if not db:923 db = self.env.get_db_cnx()924 handle_ta = True925 else:926 handle_ta = False927 880 928 cursor = db.cursor()929 self.env.log.info('Updating milestone "%s"' % self.name)930 cursor.execute("UPDATE milestone SET name=%s,due=%s,"931 "completed=%s,description=%s WHERE name=%s",932 (self.name, to_timestamp(self.due), to_timestamp(self.completed),933 self.description, self._old['name']))934 self.env.log.info('Updating milestone field of all tickets '935 'associated with milestone "%s"' % self.name)936 cursor.execute("UPDATE ticket SET milestone=%s WHERE milestone=%s",937 (self.name, self._old['name']))938 TicketSystem(self.env).reset_ticket_fields(db)939 940 if handle_ta:941 db.commit()881 @with_transaction(self.env, db) 882 def do_insert(db): 883 cursor = db.cursor() 884 self.env.log.info('Updating milestone "%s"' % self.name) 885 cursor.execute("UPDATE milestone SET name=%s,due=%s," 886 "completed=%s,description=%s WHERE name=%s", 887 (self.name, to_timestamp(self.due), 888 to_timestamp(self.completed), 889 self.description, self._old['name'])) 890 self.env.log.info('Updating milestone field of all tickets ' 891 'associated with milestone "%s"' % self.name) 892 cursor.execute("UPDATE ticket SET milestone=%s WHERE milestone=%s", 893 (self.name, self._old['name'])) 894 TicketSystem(self.env).reset_ticket_fields(db) 942 895 943 896 old_values = dict((k, v) for k, v in self._old.iteritems() 944 897 if getattr(self, k) != v) … … class Version(object): 1000 953 raise ResourceNotFound(_('Version %(name)s does not exist.', 1001 954 name=name)) 1002 955 self.name = self._old_name = name 1003 self.time = row[0] and datetime.fromtimestamp(int(row[0]), utc) or None 956 self.time = row[0] and datetime.fromtimestamp(int(row[0]), utc) \ 957 or None 1004 958 self.description = row[1] or '' 1005 959 else: 1006 960 self.name = self._old_name = None … … class Version(object): 1011 965 1012 966 def delete(self, db=None): 1013 967 assert self.exists, 'Cannot delete non-existent version' 1014 if not db:1015 db = self.env.get_db_cnx()1016 handle_ta = True1017 else:1018 handle_ta = False1019 968 1020 cursor = db.cursor() 1021 self.env.log.info('Deleting version %s' % self.name) 1022 cursor.execute("DELETE FROM version WHERE name=%s", (self.name,)) 1023 self.name = self._old_name = None 1024 TicketSystem(self.env).reset_ticket_fields(db) 1025 1026 if handle_ta: 1027 db.commit() 969 @with_transaction(self.env, db) 970 def do_delete(db): 971 cursor = db.cursor() 972 self.env.log.info('Deleting version %s' % self.name) 973 cursor.execute("DELETE FROM version WHERE name=%s", (self.name,)) 974 self.name = self._old_name = None 975 TicketSystem(self.env).reset_ticket_fields(db) 1028 976 1029 977 def insert(self, db=None): 1030 978 assert not self.exists, 'Cannot insert existing version' 1031 979 self.name = simplify_whitespace(self.name) 1032 980 if not self.name: 1033 981 raise TracError(_('Invalid version name.')) 1034 if not db:1035 db = self.env.get_db_cnx()1036 handle_ta = True1037 else:1038 handle_ta = False1039 982 1040 cursor = db.cursor()1041 self.env.log.debug("Creating new version '%s'" % self.name)1042 cursor.execute("INSERT INTO version (name,time,description) "1043 "VALUES (%s,%s,%s)",1044 (self.name, to_timestamp(self.time), self.description))1045 self._old_name = self.name1046 TicketSystem(self.env).reset_ticket_fields(db)1047 1048 if handle_ta:1049 db.commit()983 @with_transaction(self.env, db) 984 def do_insert(db): 985 cursor = db.cursor() 986 self.env.log.debug("Creating new version '%s'" % self.name) 987 cursor.execute("INSERT INTO version (name,time,description) " 988 "VALUES (%s,%s,%s)", 989 (self.name, to_timestamp(self.time), 990 self.description)) 991 self._old_name = self.name 992 TicketSystem(self.env).reset_ticket_fields(db) 1050 993 1051 994 def update(self, db=None): 1052 995 assert self.exists, 'Cannot update non-existent version' 1053 996 self.name = simplify_whitespace(self.name) 1054 997 if not self.name: 1055 998 raise TracError(_('Invalid version name.')) 1056 if not db:1057 db = self.env.get_db_cnx()1058 handle_ta = True1059 else:1060 handle_ta = False1061 999 1062 cursor = db.cursor() 1063 self.env.log.info('Updating version "%s"' % self.name) 1064 cursor.execute("UPDATE version SET name=%s,time=%s,description=%s " 1065 "WHERE name=%s", 1066 (self.name, to_timestamp(self.time), self.description, 1067 self._old_name)) 1068 if self.name != self._old_name: 1069 # Update tickets 1070 cursor.execute("UPDATE ticket SET version=%s WHERE version=%s", 1071 (self.name, self._old_name)) 1072 self._old_name = self.name 1073 TicketSystem(self.env).reset_ticket_fields(db) 1074 1075 if handle_ta: 1076 db.commit() 1000 @with_transaction(self.env, db) 1001 def do_update(db): 1002 cursor = db.cursor() 1003 self.env.log.info('Updating version "%s"' % self.name) 1004 cursor.execute("UPDATE version SET name=%s,time=%s,description=%s " 1005 "WHERE name=%s", 1006 (self.name, to_timestamp(self.time), 1007 self.description, self._old_name)) 1008 if self.name != self._old_name: 1009 # Update tickets 1010 cursor.execute("UPDATE ticket SET version=%s WHERE version=%s", 1011 (self.name, self._old_name)) 1012 self._old_name = self.name 1013 TicketSystem(self.env).reset_ticket_fields(db) 1077 1014 1078 1015 @classmethod 1079 1016 def select(cls, env, db=None): … … class Version(object): 1085 1022 for name, time, description in cursor: 1086 1023 version = cls(env) 1087 1024 version.name = version._old_name = name 1088 version.time = time and datetime.fromtimestamp(int(time), utc) or None 1025 version.time = time and datetime.fromtimestamp(int(time), utc) \ 1026 or None 1089 1027 version.description = description or '' 1090 1028 versions.append(version) 1091 1029 def version_order(v): -
trac/ticket/report.py
diff --git a/trac/ticket/report.py b/trac/ticket/report.py index 817692a..828452a 100644
a b from genshi.builder import tag 25 25 from trac.config import IntOption 26 26 from trac.core import * 27 27 from trac.db import get_column_names 28 from trac.db.util import with_transaction 28 29 from trac.mimeview import Context 29 30 from trac.perm import IPermissionRequestor 30 31 from trac.resource import Resource, ResourceNotFound … … class ReportModule(Component): 92 93 data = {} 93 94 if req.method == 'POST': 94 95 if action == 'new': 95 self._do_create(req , db)96 self._do_create(req) 96 97 elif action == 'delete': 97 self._do_delete(req, db,id)98 self._do_delete(req, id) 98 99 elif action == 'edit': 99 self._do_save(req, db,id)100 self._do_save(req, id) 100 101 elif action in ('copy', 'edit', 'new'): 101 102 template = 'report_edit.html' 102 103 data = self._render_editor(req, db, id, action=='copy') … … class ReportModule(Component): 133 134 134 135 # Internal methods 135 136 136 def _do_create(self, req , db):137 def _do_create(self, req): 137 138 req.perm.require('REPORT_CREATE') 138 139 139 140 if 'cancel' in req.args: … … class ReportModule(Component): 142 143 title = req.args.get('title', '') 143 144 query = req.args.get('query', '') 144 145 description = req.args.get('description', '') 145 cursor = db.cursor() 146 cursor.execute("INSERT INTO report (title,query,description) " 147 "VALUES (%s,%s,%s)", (title, query, description)) 148 id = db.get_last_id(cursor, 'report') 149 db.commit() 146 report_id = [ None ] 147 @with_transaction(self.env) 148 def do_create(db): 149 cursor = db.cursor() 150 cursor.execute("INSERT INTO report (title,query,description) " 151 "VALUES (%s,%s,%s)", (title, query, description)) 152 report_id[0] = db.get_last_id(cursor, 'report') 150 153 add_notice(req, _('The report has been created.')) 151 req.redirect(req.href.report( id))154 req.redirect(req.href.report(report_id[0])) 152 155 153 def _do_delete(self, req, db,id):156 def _do_delete(self, req, id): 154 157 req.perm.require('REPORT_DELETE') 155 158 156 159 if 'cancel' in req.args: 157 160 req.redirect(req.href.report(id)) 158 161 159 cursor = db.cursor() 160 cursor.execute("DELETE FROM report WHERE id=%s", (id,)) 161 db.commit() 162 @with_transaction(self.env) 163 def do_delete(db): 164 cursor = db.cursor() 165 cursor.execute("DELETE FROM report WHERE id=%s", (id,)) 162 166 add_notice(req, _('The report {%(id)d} has been deleted.', id=id)) 163 167 req.redirect(req.href.report()) 164 168 165 def _do_save(self, req, db,id):169 def _do_save(self, req, id): 166 170 """Save report changes to the database""" 167 171 req.perm.require('REPORT_MODIFY') 168 172 … … class ReportModule(Component): 170 174 title = req.args.get('title', '') 171 175 query = req.args.get('query', '') 172 176 description = req.args.get('description', '') 173 cursor = db.cursor() 174 cursor.execute("UPDATE report SET title=%s,query=%s,description=%s " 175 "WHERE id=%s", (title, query, description, id)) 176 db.commit() 177 @with_transaction(self.env) 178 def do_save(db): 179 cursor = db.cursor() 180 cursor.execute("UPDATE report " 181 "SET title=%s,query=%s,description=%s " 182 "WHERE id=%s", (title, query, description, id)) 177 183 add_notice(req, _('Your changes have been saved.')) 178 184 req.redirect(req.href.report(id)) 179 185 -
trac/ticket/roadmap.py
diff --git a/trac/ticket/roadmap.py b/trac/ticket/roadmap.py index e8f896e..9bc1431 100644
a b from trac import __version__ 26 26 from trac.attachment import AttachmentModule 27 27 from trac.config import ExtensionOption 28 28 from trac.core import * 29 from trac.db.util import with_transaction 29 30 from trac.mimeview import Context 30 31 from trac.perm import IPermissionRequestor 31 32 from trac.resource import * … … class MilestoneModule(Component): 587 588 elif action == 'edit': 588 589 return self._do_save(req, db, milestone) 589 590 elif action == 'delete': 590 self._do_delete(req, db,milestone)591 self._do_delete(req, milestone) 591 592 elif action in ('new', 'edit'): 592 593 return self._render_editor(req, db, milestone) 593 594 elif action == 'delete': … … class MilestoneModule(Component): 600 601 601 602 # Internal methods 602 603 603 def _do_delete(self, req, db,milestone):604 def _do_delete(self, req, milestone): 604 605 req.perm(milestone.resource).require('MILESTONE_DELETE') 605 606 606 607 retarget_to = None 607 608 if req.args.has_key('retarget'): 608 609 retarget_to = req.args.get('target') or None 609 610 milestone.delete(retarget_to, req.authname) 610 db.commit()611 611 add_notice(req, _('The milestone "%(name)s" has been deleted.', 612 612 name=milestone.name)) 613 613 req.redirect(req.href.roadmap()) … … class MilestoneModule(Component): 671 671 milestone.update() 672 672 # eventually retarget opened tickets associated with the milestone 673 673 if 'retarget' in req.args and completed: 674 cursor = db.cursor() 675 cursor.execute("UPDATE ticket SET milestone=%s WHERE " 676 "milestone=%s and status != 'closed'", 677 (retarget_to, old_name)) 678 self.env.log.info('Tickets associated with milestone %s ' 679 'retargeted to %s' % (old_name, retarget_to)) 674 @with_transaction(self.env) 675 def retarget(db): 676 cursor = db.cursor() 677 cursor.execute("UPDATE ticket SET milestone=%s WHERE " 678 "milestone=%s and status != 'closed'", 679 (retarget_to, old_name)) 680 self.env.log.info('Tickets associated with milestone %s ' 681 'retargeted to %s' 682 % (old_name, retarget_to)) 680 683 else: 681 684 milestone.insert() 682 db.commit()683 685 684 686 add_notice(req, _('Your changes have been saved.')) 685 687 req.redirect(req.href.milestone(milestone.name)) -
trac/versioncontrol/api.py
diff --git a/trac/versioncontrol/api.py b/trac/versioncontrol/api.py index 4d2f06e..1727603 100644
a b except ImportError: 26 26 from trac.admin import AdminCommandError, IAdminCommandProvider 27 27 from trac.config import ListOption, Option 28 28 from trac.core import * 29 from trac.db.util import with_transaction 29 30 from trac.resource import IResourceManager, Resource, ResourceNotFound 30 31 from trac.util.text import printout, to_unicode 31 32 from trac.util.translation import _ … … class DbRepositoryProvider(Component): 206 207 if type_ and type_ not in rm.get_supported_types(): 207 208 raise TracError(_("The repository type '%(type)s' is not " 208 209 "supported", type=type_)) 209 db = self.env.get_db_cnx()210 id = rm.get_repository_id(reponame, db)211 cursor = db.cursor()212 cursor.executemany("INSERT INTO repository (id, name, value) "213 "VALUES (%s, %s, %s)",214 [(id, 'dir', dir),215 (id, 'type', type_ or '')])216 db.commit()210 @with_transaction(self.env) 211 def do_add(db): 212 id = rm.get_repository_id(reponame, db) 213 cursor = db.cursor() 214 cursor.executemany("INSERT INTO repository (id, name, value) " 215 "VALUES (%s, %s, %s)", 216 [(id, 'dir', dir), 217 (id, 'type', type_ or '')]) 217 218 rm.reload_repositories() 218 219 219 220 def add_alias(self, reponame, target): … … class DbRepositoryProvider(Component): 223 224 if is_default(target): 224 225 target = '' 225 226 rm = RepositoryManager(self.env) 226 db = self.env.get_db_cnx()227 id = rm.get_repository_id(reponame, db)228 cursor = db.cursor()229 cursor.executemany("INSERT INTO repository (id, name, value) "230 "VALUES (%s, %s, %s)",231 [(id, 'dir', None),232 (id, 'alias', target)])233 db.commit()227 @with_transaction(self.env) 228 def do_add(db): 229 id = rm.get_repository_id(reponame, db) 230 cursor = db.cursor() 231 cursor.executemany("INSERT INTO repository (id, name, value) " 232 "VALUES (%s, %s, %s)", 233 [(id, 'dir', None), 234 (id, 'alias', target)]) 234 235 rm.reload_repositories() 235 236 236 237 def remove_repository(self, reponame): … … class DbRepositoryProvider(Component): 238 239 if is_default(reponame): 239 240 reponame = '' 240 241 rm = RepositoryManager(self.env) 241 db = self.env.get_db_cnx()242 id = rm.get_repository_id(reponame, db)243 cursor = db.cursor()244 cursor.execute("DELETE FROM repository WHERE id=%s", (id,))245 cursor.execute("DELETE FROM revision WHERE repos=%s", (id,))246 cursor.execute("DELETE FROM node_changeWHERE repos=%s", (id,))247 db.commit()242 @with_transaction(self.env) 243 def do_remove(db): 244 id = rm.get_repository_id(reponame, db) 245 cursor = db.cursor() 246 cursor.execute("DELETE FROM repository WHERE id=%s", (id,)) 247 cursor.execute("DELETE FROM revision WHERE repos=%s", (id,)) 248 cursor.execute("DELETE FROM node_change WHERE repos=%s", (id,)) 248 249 rm.reload_repositories() 249 250 250 251 def modify_repository(self, reponame, changes): … … class DbRepositoryProvider(Component): 252 253 if is_default(reponame): 253 254 reponame = '' 254 255 rm = RepositoryManager(self.env) 255 db = self.env.get_db_cnx()256 id = rm.get_repository_id(reponame, db)257 cursor = db.cursor()258 for (k, v) in changes.iteritems():259 if k not in self.repository_attrs:260 continue261 if k in('alias', 'name') and is_default(v):262 v = ''263 cursor.execute("UPDATE repository SET value=%s "264 "WHERE id=%s AND name=%s", (v, id, k))265 cursor.execute("SELECT value FROM repository "266 "WHERE id=%s AND name=%s", (id, k))267 if not cursor.fetchone():268 cursor.execute("INSERT INTO repository (id, name, value) "269 "VALUES (%s, %s, %s)", (id, k, v))270 db.commit()256 @with_transaction(self.env) 257 def do_modify(db): 258 cursor = db.cursor() 259 id = rm.get_repository_id(reponame, db) 260 for (k, v) in changes.iteritems(): 261 if k not in self.repository_attrs: 262 continue 263 if k in('alias', 'name') and is_default(v): 264 v = '' 265 cursor.execute("UPDATE repository SET value=%s " 266 "WHERE id=%s AND name=%s", (v, id, k)) 267 cursor.execute("SELECT value FROM repository " 268 "WHERE id=%s AND name=%s", (id, k)) 269 if not cursor.fetchone(): 270 cursor.execute("INSERT INTO repository (id, name, value) " 271 "VALUES (%s, %s, %s)", (id, k, v)) 271 272 rm.reload_repositories() 272 273 273 274 … … class RepositoryManager(Component): 460 461 id = cursor.fetchone()[0] + 1 461 462 cursor.execute("INSERT INTO repository (id, name, value) " 462 463 "VALUES (%s,%s,%s)", (id, 'name', reponame)) 463 if handle_ta:464 db.commit()465 464 return id 466 465 467 466 def get_repository(self, reponame): -
trac/versioncontrol/cache.py
diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py index 0618f4e..6028feb 100644
a b import os 19 19 20 20 from trac.cache import CacheProxy 21 21 from trac.core import TracError 22 from trac.db.util import with_transaction 22 23 from trac.util.datefmt import utc, to_timestamp 23 24 from trac.util.translation import _ 24 25 from trac.versioncontrol import Changeset, Node, Repository, NoSuchChangeset … … class CachedRepository(Repository): 84 85 85 86 def sync_changeset(self, rev): 86 87 cset = self.repos.get_changeset(rev) 87 db = self.env.get_db_cnx() 88 cursor = db.cursor() 89 cursor.execute("SELECT time,author,message FROM revision " 90 "WHERE repos=%s AND rev=%s", 91 (self.id, str(cset.rev))) 92 old_cset = None 93 for time, author, message in cursor: 94 date = datetime.fromtimestamp(time, utc) 95 old_cset = Changeset(self.repos, cset.rev, message, author, date) 96 97 cursor.execute("UPDATE revision SET time=%s, author=%s, message=%s " 98 "WHERE repos=%s AND rev=%s", 99 (to_timestamp(cset.date), cset.author, cset.message, 100 self.id, str(cset.rev))) 101 db.commit() 102 return old_cset 88 old_cset = [None] 89 90 @with_transaction(self.env) 91 def do_sync(db): 92 cursor = db.cursor() 93 cursor.execute(""" 94 SELECT time,author,message FROM revision 95 WHERE repos=%s AND rev=%s 96 """, (self.id, str(cset.rev))) 97 for time, author, message in cursor: 98 date = datetime.fromtimestamp(time, utc) 99 old_cset[0] = Changeset(self.repos, cset.rev, message, author, 100 date) 101 cursor.execute(""" 102 UPDATE revision SET time=%s, author=%s, message=%s 103 WHERE repos=%s AND rev=%s 104 """, (to_timestamp(cset.date), cset.author, 105 cset.message, self.id, str(cset.rev))) 106 return old_cset[0] 103 107 104 108 def _metadata(self, db): 105 109 """Retrieve data for the cached `metadata` attribute.""" -
trac/web/auth.py
diff --git a/trac/web/auth.py b/trac/web/auth.py index 803a674..66dc092 100644
a b from genshi.builder import tag 32 32 33 33 from trac.config import BoolOption, IntOption 34 34 from trac.core import * 35 from trac.db.util import with_transaction 35 36 from trac.web.api import IAuthenticator, IRequestHandler 36 37 from trac.web.chrome import INavigationContributor 37 38 from trac.util import hex_entropy, md5, md5crypt … … class LoginModule(Component): 146 147 _('Already logged in as %(user)s.', user=req.authname) 147 148 148 149 cookie = hex_entropy() 149 db = self.env.get_db_cnx()150 cursor = db.cursor()151 cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) "152 "VALUES (%s, %s, %s, %s)", (cookie, remote_user,153 req.remote_addr, int(time.time())))154 db.commit()155 150 @with_transaction(self.env) 151 def store_session_cookie(db): 152 cursor = db.cursor() 153 cursor.execute("INSERT INTO auth_cookie (cookie,name,ipnr,time) " 154 "VALUES (%s, %s, %s, %s)", 155 (cookie, remote_user, 156 req.remote_addr, int(time.time()))) 156 157 req.authname = remote_user 157 158 req.outcookie['trac_auth'] = cookie 158 159 req.outcookie['trac_auth']['path'] = req.base_path or '/' … … class LoginModule(Component): 172 173 173 174 # While deleting this cookie we also take the opportunity to delete 174 175 # cookies older than 10 days 175 db = self.env.get_db_cnx() 176 cursor = db.cursor() 177 cursor.execute("DELETE FROM auth_cookie WHERE name=%s OR time < %s", 178 (req.authname, int(time.time()) - 86400 * 10)) 179 db.commit() 176 @with_transaction(self.env) 177 def delete_session_cookie(db): 178 cursor = db.cursor() 179 cursor.execute("DELETE FROM auth_cookie " 180 "WHERE name=%s OR time < %s", 181 (req.authname, int(time.time()) - 86400 * 10)) 180 182 self._expire_cookie(req) 181 183 custom_redirect = self.config['metanav'].get('logout.redirect') 182 184 if custom_redirect: -
trac/web/session.py
diff --git a/trac/web/session.py b/trac/web/session.py index 07e47e1..cf93752 100644
a b 21 21 import time 22 22 23 23 from trac.core import TracError 24 from trac.db.util import with_transaction 24 25 from trac.util import hex_entropy 25 26 from trac.util.html import Markup 26 27 … … class DetachedSession(dict): 78 79 79 80 authenticated = int(self.authenticated) 80 81 now = int(time.time()) 81 db = self.env.get_db_cnx()82 cursor = db.cursor()83 82 84 if self._new: 85 self.last_visit = now 86 self._new = False 87 # The session might already exist even if _new is True since 88 # it could have been created by a concurrent request (#3563). 89 try: 90 cursor.execute("INSERT INTO session (sid,last_visit,authenticated)" 91 " VALUES(%s,%s,%s)", 92 (self.sid, self.last_visit, authenticated)) 93 except Exception, e: 94 db.rollback() 95 self.env.log.warning('Session %s already exists: %s' % 96 (self.sid, e)) 97 if self._old != self: 98 attrs = [(self.sid, authenticated, k, v) for k, v in self.items()] 99 cursor.execute("DELETE FROM session_attribute WHERE sid=%s", 100 (self.sid,)) 101 self._old = dict(self.items()) 102 if attrs: 103 # The session variables might already have been updated by a 104 # concurrent request. 83 @with_transaction(self.env) 84 def delete_session_cookie(db): 85 cursor = db.cursor() 86 if self._new: 87 self.last_visit = now 88 self._new = False 89 # The session might already exist even if _new is True since 90 # it could have been created by a concurrent request (#3563). 105 91 try: 106 cursor.executemany("INSERT INTO session_attribute " 107 "(sid,authenticated,name,value) " 108 "VALUES(%s,%s,%s,%s)", attrs) 109 except Exception, e: 92 cursor.execute("INSERT INTO session " 93 " (sid,last_visit,authenticated)" 94 " VALUES (%s,%s,%s)", 95 (self.sid, self.last_visit, authenticated)) 96 except Exception: 110 97 db.rollback() 111 self.env.log.warning('Attributes for session %s already ' 112 'updated: %s' % (self.sid, e)) 113 elif not authenticated: 114 # No need to keep around empty unauthenticated sessions 115 cursor.execute("DELETE FROM session " 116 "WHERE sid=%s AND authenticated=0", (self.sid,)) 117 db.commit() 118 return 119 120 # Update the session last visit time if it is over an hour old, 121 # so that session doesn't get purged 122 if now - self.last_visit > UPDATE_INTERVAL: 123 self.last_visit = now 124 self.env.log.info("Refreshing session %s" % self.sid) 125 cursor.execute('UPDATE session SET last_visit=%s ' 126 'WHERE sid=%s AND authenticated=%s', 127 (self.last_visit, self.sid, authenticated)) 128 # Purge expired sessions. We do this only when the session was 129 # changed as to minimize the purging. 130 mintime = now - PURGE_AGE 131 self.env.log.debug('Purging old, expired, sessions.') 132 cursor.execute("DELETE FROM session_attribute " 133 "WHERE authenticated=0 AND sid " 134 "IN (SELECT sid FROM session WHERE " 135 "authenticated=0 AND last_visit < %s)", 136 (mintime,)) 137 cursor.execute("DELETE FROM session WHERE " 138 "authenticated=0 AND last_visit < %s", 139 (mintime,)) 140 db.commit() 98 self.env.log.warning('Session %s already exists', self.sid) 99 if self._old != self: 100 attrs = [(self.sid, authenticated, k, v) 101 for k, v in self.items()] 102 cursor.execute("DELETE FROM session_attribute WHERE sid=%s", 103 (self.sid,)) 104 self._old = dict(self.items()) 105 if attrs: 106 # The session variables might already have been updated 107 # by a concurrent request. 108 try: 109 cursor.executemany("INSERT INTO session_attribute " 110 " (sid,authenticated,name,value) " 111 " VALUES (%s,%s,%s,%s)", attrs) 112 except Exception: 113 db.rollback() 114 self.env.log.warning('Attributes for session %s ' 115 'already updated', self.sid) 116 elif not authenticated: 117 # No need to keep around empty unauthenticated sessions 118 cursor.execute("DELETE FROM session " 119 "WHERE sid=%s AND authenticated=0", 120 (self.sid,)) 121 return 122 # Update the session last visit time if it is over an hour old, 123 # so that session doesn't get purged 124 if now - self.last_visit > UPDATE_INTERVAL: 125 self.last_visit = now 126 self.env.log.info("Refreshing session %s", self.sid) 127 cursor.execute('UPDATE session SET last_visit=%s ' 128 'WHERE sid=%s AND authenticated=%s', 129 (self.last_visit, self.sid, authenticated)) 130 # Purge expired sessions. We do this only when the session was 131 # changed as to minimize the purging. 132 mintime = now - PURGE_AGE 133 self.env.log.debug('Purging old, expired, sessions.') 134 cursor.execute("DELETE FROM session_attribute " 135 "WHERE authenticated=0 AND sid " 136 "IN (SELECT sid FROM session WHERE " 137 "authenticated=0 AND last_visit < %s)", 138 (mintime,)) 139 cursor.execute("DELETE FROM session WHERE " 140 "authenticated=0 AND last_visit < %s", 141 (mintime,)) 141 142 142 143 143 144 class Session(DetachedSession): … … class Session(DetachedSession): 187 188 assert new_sid, 'Session ID cannot be empty' 188 189 if new_sid == self.sid: 189 190 return 190 db = self.env.get_db_cnx() 191 cursor = db.cursor() 191 cursor = self.env.get_db_cnx().cursor() 192 192 cursor.execute("SELECT sid FROM session WHERE sid=%s", (new_sid,)) 193 193 if cursor.fetchone(): 194 194 raise TracError(Markup('Session "%s" already exists.<br />' 195 195 'Please choose a different session ID.') 196 196 % new_sid, 'Error renaming session') 197 self.env.log.debug('Changing session ID %s to %s' % (self.sid, new_sid)) 198 cursor.execute("UPDATE session SET sid=%s WHERE sid=%s " 199 "AND authenticated=0", (new_sid, self.sid)) 200 cursor.execute("UPDATE session_attribute SET sid=%s " 201 "WHERE sid=%s and authenticated=0", 202 (new_sid, self.sid)) 203 db.commit() 197 self.env.log.debug('Changing session ID %s to %s', self.sid, new_sid) 198 199 @with_transaction(self.env) 200 def update_session_id(db): 201 cursor = db.cursor() 202 cursor.execute("UPDATE session SET sid=%s WHERE sid=%s " 203 "AND authenticated=0", (new_sid, self.sid)) 204 cursor.execute("UPDATE session_attribute SET sid=%s " 205 "WHERE sid=%s and authenticated=0", 206 (new_sid, self.sid)) 204 207 self.sid = new_sid 205 208 self.bake_cookie() 206 209 … … class Session(DetachedSession): 211 214 assert self.req.authname != 'anonymous', \ 212 215 'Cannot promote session of anonymous user' 213 216 214 db = self.env.get_db_cnx() 215 cursor = db.cursor() 216 cursor.execute("SELECT authenticated FROM session " 217 "WHERE sid=%s OR sid=%s ", (sid, self.req.authname)) 218 authenticated_flags = [row[0] for row in cursor.fetchall()] 219 220 if len(authenticated_flags) == 2: 221 # There's already an authenticated session for the user, we 222 # simply delete the anonymous session 223 cursor.execute("DELETE FROM session WHERE sid=%s " 224 "AND authenticated=0", (sid,)) 225 cursor.execute("DELETE FROM session_attribute WHERE sid=%s " 226 "AND authenticated=0", (sid,)) 227 elif len(authenticated_flags) == 1: 228 if not authenticated_flags[0]: 229 # Update the anomymous session records so that the session ID 230 # becomes the user name, and set the authenticated flag. 231 self.env.log.debug('Promoting anonymous session %s to ' 232 'authenticated session for user %s', 233 sid, self.req.authname) 234 cursor.execute("UPDATE session SET sid=%s,authenticated=1 " 235 "WHERE sid=%s AND authenticated=0", 236 (self.req.authname, sid)) 237 cursor.execute("UPDATE session_attribute " 238 "SET sid=%s,authenticated=1 WHERE sid=%s", 239 (self.req.authname, sid)) 240 else: 241 # we didn't have an anonymous session for this sid 242 cursor.execute("INSERT INTO session (sid,last_visit,authenticated)" 243 " VALUES(%s,%s,1)", 244 (self.req.authname, int(time.time()))) 217 @with_transaction(self.env) 218 def update_session_id(db): 219 cursor = db.cursor() 220 cursor.execute("SELECT authenticated FROM session " 221 "WHERE sid=%s OR sid=%s ", (sid, self.req.authname)) 222 authenticated_flags = [row[0] for row in cursor.fetchall()] 223 224 if len(authenticated_flags) == 2: 225 # There's already an authenticated session for the user, 226 # we simply delete the anonymous session 227 cursor.execute("DELETE FROM session WHERE sid=%s " 228 "AND authenticated=0", (sid,)) 229 cursor.execute("DELETE FROM session_attribute WHERE sid=%s " 230 "AND authenticated=0", (sid,)) 231 elif len(authenticated_flags) == 1: 232 if not authenticated_flags[0]: 233 # Update the anomymous session records so the session ID 234 # becomes the user name, and set the authenticated flag. 235 self.env.log.debug('Promoting anonymous session %s to ' 236 'authenticated session for user %s', 237 sid, self.req.authname) 238 cursor.execute("UPDATE session SET sid=%s,authenticated=1 " 239 "WHERE sid=%s AND authenticated=0", 240 (self.req.authname, sid)) 241 cursor.execute("UPDATE session_attribute " 242 "SET sid=%s,authenticated=1 WHERE sid=%s", 243 (self.req.authname, sid)) 244 else: 245 # we didn't have an anonymous session for this sid 246 cursor.execute("INSERT INTO session " 247 "(sid,last_visit,authenticated)" 248 " VALUES(%s,%s,1)", 249 (self.req.authname, int(time.time()))) 245 250 self._new = False 246 db.commit()247 251 248 252 self.sid = sid 249 253 self.bake_cookie(0) # expire the cookie -
trac/wiki/admin.py
diff --git a/trac/wiki/admin.py b/trac/wiki/admin.py index f8d0448..5e7ef75 100644
a b import time 19 19 20 20 from trac.admin import * 21 21 from trac.core import * 22 from trac.db.util import with_transaction 22 23 from trac.wiki import model 23 24 from trac.wiki.api import WikiSystem 24 25 from trac.util import read_file … … class WikiAdmin(Component): 118 119 data = to_unicode(data, 'utf-8') 119 120 120 121 # Make sure we don't insert the exact same page twice 121 handle_ta = not db 122 if handle_ta: 123 db = self.env.get_db_cnx() 124 cursor = db.cursor() 122 cursor = self.env.get_db_cnx().cursor() 123 125 124 cursor.execute("SELECT text FROM wiki WHERE name=%s " 126 125 "ORDER BY version DESC LIMIT 1", 127 126 (title,)) … … class WikiAdmin(Component): 133 132 printout(' %s already up to date.' % title) 134 133 return False 135 134 136 if replace and old: 137 cursor.execute("UPDATE wiki SET text=%s WHERE name=%s " 138 " AND version=(SELECT max(version) FROM wiki " 139 " WHERE name=%s)", 140 (data, title, title)) 141 else: 142 cursor.execute("INSERT INTO wiki(version,name,time,author,ipnr," 143 " text) " 144 "SELECT 1+COALESCE(max(version),0),%s,%s," 145 " 'trac','127.0.0.1',%s FROM wiki " 146 "WHERE name=%s", 147 (title, int(time.time()), data, title)) 148 if not old: 149 WikiSystem(self.env).pages.invalidate(db) 150 if handle_ta: 151 db.commit() 135 @with_transaction(self.env, db) 136 def do_import(db): 137 cursor = db.cursor() 138 if replace and old: 139 cursor.execute("UPDATE wiki SET text=%s WHERE name=%s " 140 " AND version=(SELECT max(version) FROM wiki " 141 " WHERE name=%s)", 142 (data, title, title)) 143 else: 144 cursor.execute("INSERT INTO wiki(version,name,time,author," 145 " ipnr,text) " 146 "SELECT 1+COALESCE(max(version),0),%s,%s," 147 " 'trac','127.0.0.1',%s FROM wiki " 148 "WHERE name=%s", 149 (title, int(time.time()), data, title)) 150 if not old: 151 WikiSystem(self.env).pages.invalidate(db) 152 152 return True 153 153 154 154 def load_pages(self, dir, db=None, ignore=[], create_only=[], … … class WikiAdmin(Component): 196 196 [_('Title'), _('Edits'), _('Modified')]) 197 197 198 198 def _do_remove(self, name): 199 db = self.env.get_db_cnx() 200 if name.endswith('*'): 201 pages = list(WikiSystem(self.env).get_pages(name.rstrip('*') 202 or None)) 203 for p in pages: 204 page = model.WikiPage(self.env, p, db=db) 199 @with_transaction(self.env) 200 def do_transaction(db): 201 if name.endswith('*'): 202 pages = list(WikiSystem(self.env).get_pages(name.rstrip('*') 203 or None)) 204 for p in pages: 205 page = model.WikiPage(self.env, p, db=db) 206 page.delete(db=db) 207 print_table(((p,) for p in pages), [_('Deleted pages')]) 208 else: 209 page = model.WikiPage(self.env, name, db=db) 205 210 page.delete(db=db) 206 print_table(((p,) for p in pages), [_('Deleted pages')])207 else:208 page = model.WikiPage(self.env, name, db=db)209 page.delete(db=db)210 db.commit()211 211 212 212 def _do_export(self, page, filename=None): 213 213 self.export_page(page, filename) … … class WikiAdmin(Component): 236 236 self.export_page(p, dst, cursor) 237 237 238 238 def _load_or_replace(self, paths, replace): 239 db = self.env.get_db_cnx()240 for path in paths:241 if os.path.isdir(path):242 self.load_pages(path, db, replace=replace)243 else:244 page = os.path.basename(path)245 page = unicode_unquote(page.encode('utf-8'))246 if self.import_page(path, page, db, replace=replace):247 printout(_(" %(page)s imported from %(filename)s",248 filename=path, page=page))249 db.commit()239 @with_transaction(self.env) 240 def do_transaction(db): 241 for path in paths: 242 if os.path.isdir(path): 243 self.load_pages(path, db, replace=replace) 244 else: 245 page = os.path.basename(path) 246 page = unicode_unquote(page.encode('utf-8')) 247 if self.import_page(path, page, db, replace=replace): 248 printout(_(" %(page)s imported from %(filename)s", 249 filename=path, page=page)) 250 250 251 251 def _do_load(self, *paths): 252 252 self._load_or_replace(paths, replace=False) … … class WikiAdmin(Component): 255 255 self._load_or_replace(paths, replace=True) 256 256 257 257 def _do_upgrade(self): 258 db = self.env.get_db_cnx()259 self.load_pages(pkg_resources.resource_filename('trac.wiki',260 'default-pages'),261 db, ignore=['WikiStart', 'checkwiki.py'],262 create_only=['InterMapTxt'])263 db.commit()258 @with_transaction(self.env) 259 def do_transaction(db): 260 self.load_pages(pkg_resources.resource_filename('trac.wiki', 261 'default-pages'), 262 db, ignore=['WikiStart', 'checkwiki.py'], 263 create_only=['InterMapTxt']) -
trac/wiki/model.py
diff --git a/trac/wiki/model.py b/trac/wiki/model.py index cb29395..d8183df 100644
a b 19 19 from datetime import datetime 20 20 21 21 from trac.core import * 22 from trac.db.util import with_transaction 22 23 from trac.resource import Resource 23 24 from trac.util.datefmt import utc, to_timestamp 24 25 from trac.util.translation import _ … … class WikiPage(object): 78 79 self.text = self.comment = self.author = '' 79 80 self.time = None 80 81 self.readonly = 0 81 82 82 83 exists = property(fget=lambda self: self.version > 0) 83 84 84 85 def delete(self, version=None, db=None): 85 86 assert self.exists, 'Cannot delete non-existent page' 86 if not db: 87 db = self.env.get_db_cnx() 88 handle_ta = True 89 else: 90 handle_ta = False 91 92 cursor = db.cursor() 93 if version is None: 94 # Delete a wiki page completely 95 cursor.execute("DELETE FROM wiki WHERE name=%s", (self.name,)) 96 self.env.log.info('Deleted page %s' % self.name) 97 else: 98 # Delete only a specific page version 99 cursor.execute("DELETE FROM wiki WHERE name=%s and version=%s", 100 (self.name, version)) 101 self.env.log.info('Deleted version %d of page %s' 102 % (version, self.name)) 103 104 if version is None or version == self.version: 105 self._fetch(self.name, None, db) 106 107 if not self.exists: 108 # Invalidate page name cache 109 WikiSystem(self.env).pages.invalidate(db) 110 # Delete orphaned attachments 111 from trac.attachment import Attachment 112 Attachment.delete_all(self.env, 'wiki', self.name, db) 113 114 if handle_ta: 115 db.commit() 87 88 @with_transaction(self.env, db) 89 def do_delete(db): 90 cursor = db.cursor() 91 if version is None: 92 # Delete a wiki page completely 93 cursor.execute("DELETE FROM wiki WHERE name=%s", (self.name,)) 94 self.env.log.info('Deleted page %s' % self.name) 95 else: 96 # Delete only a specific page version 97 cursor.execute("DELETE FROM wiki WHERE name=%s and version=%s", 98 (self.name, version)) 99 self.env.log.info('Deleted version %d of page %s' 100 % (version, self.name)) 101 102 if version is None or version == self.version: 103 self._fetch(self.name, None, db) 104 105 if not self.exists: 106 # Invalidate page name cache 107 WikiSystem(self.env).pages.invalidate(db) 108 # Delete orphaned attachments 109 from trac.attachment import Attachment 110 Attachment.delete_all(self.env, 'wiki', self.name, db) 116 111 117 112 # Let change listeners know about the deletion 118 113 if not self.exists: … … class WikiPage(object): 124 119 listener.wiki_page_version_deleted(self) 125 120 126 121 def save(self, author, comment, remote_addr, t=None, db=None): 127 if not db: 128 db = self.env.get_db_cnx() 129 handle_ta = True 130 else: 131 handle_ta = False 132 133 if t is None: 134 t = datetime.now(utc) 135 136 if self.text != self.old_text: 137 cursor = db.cursor() 138 cursor.execute("INSERT INTO wiki (name,version,time,author,ipnr," 139 "text,comment,readonly) VALUES (%s,%s,%s,%s,%s,%s," 140 "%s,%s)", (self.name, self.version + 1, 141 to_timestamp(t), author, remote_addr, 142 self.text, comment, self.readonly)) 143 self.version += 1 144 self.resource = self.resource(version=self.version) 145 elif self.readonly != self.old_readonly: 146 cursor = db.cursor() 147 cursor.execute("UPDATE wiki SET readonly=%s WHERE name=%s", 148 (self.readonly, self.name)) 149 else: 122 new_text = self.text != self.old_text 123 if not new_text and self.readonly == self.old_readonly: 150 124 raise TracError(_('Page not modified')) 125 t = t or datetime.now(utc) 151 126 152 if self.version == 1: 153 # Invalidate page name cache 154 WikiSystem(self.env).pages.invalidate(db) 155 156 if handle_ta: 157 db.commit() 127 @with_transaction(self.env, db) 128 def do_save(db): 129 cursor = db.cursor() 130 if new_text: 131 cursor.execute("INSERT INTO wiki (name,version,time," 132 "author,ipnr,text,comment,readonly)" 133 "VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", 134 (self.name, self.version + 1, to_timestamp(t), 135 author, remote_addr, self.text, comment, 136 self.readonly)) 137 self.version += 1 138 self.resource = self.resource(version=self.version) 139 else: 140 cursor.execute("UPDATE wiki SET readonly=%s WHERE name=%s", 141 (self.readonly, self.name)) 142 if self.version == 1: 143 # Invalidate page name cache 144 WikiSystem(self.env).pages.invalidate(db) 158 145 159 146 self.author = author 160 147 self.comment = comment -
trac/wiki/web_ui.py
diff --git a/trac/wiki/web_ui.py b/trac/wiki/web_ui.py index 282dbeb..d8a69fe 100644
a b from genshi.builder import tag 25 25 from trac.attachment import AttachmentModule 26 26 from trac.config import IntOption 27 27 from trac.core import * 28 from trac.db.util import with_transaction 28 29 from trac.mimeview.api import Mimeview, IContentConverter, Context 29 30 from trac.perm import IPermissionRequestor 30 31 from trac.resource import * … … class WikiModule(Component): 244 245 version = int(req.args.get('version', 0)) or None 245 246 old_version = int(req.args.get('old_version', 0)) or version 246 247 247 db = self.env.get_db_cnx()248 if version and old_version and version > old_version:249 # delete from `old_version` exclusive to `version` inclusive:250 for v in range(old_version, version):251 page.delete(v + 1, db)252 else:253 # only delete that `version`, or the whole page if `None`254 page.delete(version, db)255 db.commit()248 @with_transaction(self.env) 249 def do_transaction(db): 250 if version and old_version and version > old_version: 251 # delete from `old_version` exclusive to `version` inclusive: 252 for v in range(old_version, version): 253 page.delete(v + 1, db) 254 else: 255 # only delete that `version`, or the whole page if `None` 256 page.delete(version, db) 256 257 257 258 if not page.exists: 258 259 add_notice(req, _('The page %(name)s has been deleted.',
