def _get_help_href(self, req): if not self.help_opt: return None link = resource_id = None if self.help_opt.startswith('/'): # Assume valid URL to arbitrary resource inside # of the current Trac environment. link = req.href(self.help_opt) if not link and ':' in self.help_opt: realm, resource_id = self.help_opt.split(':', 1) # Validate realm-like prefix against resource realm list, # but exclude 'wiki' to allow deferred page creation. rsys = ResourceSystem(self.env) if realm in set(rsys.get_known_realms()) - set('wiki'): mgr = rsys.get_resource_manager(realm) # Handle optional IResourceManager method gracefully. try: if mgr.resource_exists(Resource(realm, resource_id)): link = mgr.get_resource_url(resource_id, req.href) except AttributeError: # Assume generic resource URL build rule. link = req.href(realm, resource_id) if not link: if not resource_id: # Assume wiki page name for backwards-compatibility. resource_id = self.help_opt if '#' in resource_id: path, anchor = resource_id.split('#', 1) anchor = unicode_quote_plus(anchor, safe="?!~*'()") link = '#'.join((req.href.wiki(path), anchor)) else: link = req.href.wiki(resource_id) return link
def make_trac_environment_with_plugin(): env = EnvironmentStub(enable=["movie.*", MovieMacro, MoviePreviewRenderer]) resource_system = ResourceSystem(env) resource_system._resource_managers_map = { 'attachment': AttachmentModule(env), } movie_macro = MovieMacro(env) preview_renderer = MoviePreviewRenderer(env) return env, movie_macro, preview_renderer
def resource_from_page(env, page): resource_realm = None resources = ResourceSystem(env) for realm in resources.get_known_realms(): if page.startswith('/' + realm): resource_realm = realm break if resource_realm is not None: return (resource_realm, re.sub('/' + resource_realm, '', page).lstrip('/')) else: return page, None
def resource_exists(env, resource): """Checks for resource existence without actually instantiating a model. :return: `True` if the resource exists, `False` if it doesn't and `None` in case no conclusion could be made (i.e. when `IResourceManager.resource_exists` is not implemented). """ manager = ResourceSystem(env).get_resource_manager(resource.realm) if manager and hasattr(manager, 'resource_exists'): return manager.resource_exists(resource) elif resource.id is None: return False
def delete(self, retarget_to=None, author=None, db=None): """Delete the milestone. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ with self.env.db_transaction as db: self.env.log.info("Deleting milestone %s", self.name) db("DELETE FROM milestone WHERE name=%s", (self.name, )) # Retarget/reset tickets associated with this milestone now = datetime.now(utc) tkt_ids = [ int(row[0]) for row in db("SELECT id FROM ticket WHERE milestone=%s", ( self.name, )) ] for tkt_id in tkt_ids: ticket = Ticket(self.env, tkt_id, db) ticket['milestone'] = retarget_to comment = "Milestone %s deleted" % self.name # don't translate ticket.save_changes(author, comment, now) self._old['name'] = None del self.cache.milestones TicketSystem(self.env).reset_ticket_fields() for listener in TicketSystem(self.env).milestone_change_listeners: listener.milestone_deleted(self) ResourceSystem(self.env).resource_deleted(self)
def rename(self, new_name): """Rename wiki page in-place, keeping the history intact. Renaming a page this way will eventually leave dangling references to the old page - which litterally doesn't exist anymore. """ assert self.exists, "Cannot rename non-existent page" if not validate_page_name(new_name): raise TracError( _("Invalid Wiki page name '%(name)s'", name=new_name)) old_name = self.name with self.env.db_transaction as db: new_page = WikiPage(self.env, new_name) if new_page.exists: raise TracError( _("Can't rename to existing %(name)s page.", name=new_name)) db("UPDATE wiki SET name=%s WHERE name=%s", (new_name, old_name)) # Invalidate page name cache del WikiSystem(self.env).pages # Reparent attachments from trac.attachment import Attachment Attachment.reparent_all(self.env, 'wiki', old_name, 'wiki', new_name) self.name = new_name self.env.log.info('Renamed page %s to %s', old_name, new_name) for listener in WikiSystem(self.env).change_listeners: if hasattr(listener, 'wiki_page_renamed'): listener.wiki_page_renamed(self, old_name) ResourceSystem(self.env).resource_changed(self, dict(name=old_name))
def _get_env_for_resource(self, resource): if hasattr(resource, "neighborhood"): env = ResourceSystem(self.env).load_component_manager( resource.neighborhood) else: env = self.env return env
def update(self, db=None): """Update the component. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert self.exists, "Cannot update non-existent component" self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid component name.")) old_name = self._old_name with self.env.db_transaction as db: self.env.log.info("Updating component '%s'", self.name) db( """UPDATE component SET name=%s,owner=%s, description=%s WHERE name=%s """, (self.name, self.owner, self.description, self._old_name)) if self.name != self._old_name: # Update tickets db("UPDATE ticket SET component=%s WHERE component=%s", (self.name, self._old_name)) self._old_name = self.name TicketSystem(self.env).reset_ticket_fields() #todo:add support of old_values for owner and description fields old_values = dict() if self.name != old_name: old_values["name"] = old_name ResourceSystem(self.env).resource_changed(self, old_values)
def update(self, author=None): """Update the matching record in the database""" if self._old_data == self._data: return if not self._exists: raise TracError('%(object_name)s does not exist' % self._meta) for key in self._meta['no_change_fields']: if self._data[key] != self._old_data[key]: raise TracError('%s cannot be changed' % key) for key in self._key_fields + self._unique_fields: if self._data[key] != self._old_data[key]: if len(self.select(self._env, where = {key:self._data[key]})): raise TracError('%s already exists' % key) setsql, setvalues = fields_to_kv_str(self._env, self._non_key_fields, self._data, sep=',') where, values = fields_to_kv_str(self._env, self._key_fields, self._data) sdata = {'where': where, 'values': setsql} sdata.update(self._meta) sql = """UPDATE %(table_name)s SET %(values)s WHERE %(where)s""" % sdata old_values = dict((k, v) for k, v in self._old_data.iteritems() if self._data.get(k) != v) with self._env.db_transaction as db: db(sql, setvalues + values) self._update_relations(db, author) self._old_data.update(self._data) TicketSystem(self._env).reset_ticket_fields() ResourceSystem(self._env).resource_changed(self, old_values)
def update(self, db=None): """Update the enum value. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert self.exists, "Cannot update non-existent %s" % self.type self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid %(type)s name.", type=self.type)) with self.env.db_transaction as db: self.env.log.info("Updating %s '%s'", self.type, self.name) db("UPDATE enum SET name=%s,value=%s WHERE type=%s AND name=%s", (self.name, self.value, self.type, self._old_name)) if self.name != self._old_name: # Update tickets db( "UPDATE ticket SET %s=%%s WHERE %s=%%s" % (self.ticket_col, self.ticket_col), (self.name, self._old_name)) TicketSystem(self.env).reset_ticket_fields() old_values = dict() if self.name != self._old_name: old_values["name"] = self._old_name if self.value != self._old_value: old_values["value"] = self._old_value self._old_name = self.name self._old_value = self.value ResourceSystem(self.env).resource_changed(self, old_values)
def insert(self, db=None): """Add a new enum value. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert not self.exists, "Cannot insert existing %s" % self.type self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_('Invalid %(type)s name.', type=self.type)) with self.env.db_transaction as db: self.env.log.debug("Creating new %s '%s'", self.type, self.name) if not self.value: row = db( "SELECT COALESCE(MAX(%s), 0) FROM enum WHERE type=%%s" % db.cast('value', 'int'), (self.type, )) self.value = int(float(row[0][0])) + 1 if row else 0 db("INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)", (self.type, self.name, self.value)) TicketSystem(self.env).reset_ticket_fields() self._old_name = self.name self._old_value = self.value ResourceSystem(self.env).resource_created(self)
def delete(self, db=None): """Delete the enum value. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert self.exists, "Cannot delete non-existent %s" % self.type with self.env.db_transaction as db: self.env.log.info("Deleting %s %s", self.type, self.name) db("DELETE FROM enum WHERE type=%s AND value=%s", (self.type, self._old_value)) # Re-order any enums that have higher value than deleted # (close gap) for enum in self.select(self.env): try: if int(enum.value) > int(self._old_value): enum.value = unicode(int(enum.value) - 1) enum.update() except ValueError: pass # Ignore cast error for this non-essential operation TicketSystem(self.env).reset_ticket_fields() ResourceSystem(self.env).resource_deleted(self) self.value = self._old_value = None self.name = self._old_name = None
def insert(self): """Create new record in the database""" sdata = None if self._exists or len( self.select(self._env, where=dict([(k, self._data[k]) for k in self._key_fields]))): sdata = { 'keys': ','.join( ["%s='%s'" % (k, self._data[k]) for k in self._key_fields]) } elif self._unique_fields and len( self.select(self._env, where=dict([(k, self._data[k]) for k in self._unique_fields]))): sdata = { 'keys': ','.join([ "%s='%s'" % (k, self._data[k]) for k in self._unique_fields ]) } if sdata: sdata.update(self._meta) sdata['values'] = self._data raise TracError( '%(object_name)s %(keys)s already exists %(values)s' % sdata) for key in self._key_fields: if self._data[key] is None and key not in self._auto_inc_fields: sdata = {'key': key} sdata.update(self._meta) raise TracError('%(key)s required for %(object_name)s' % sdata) fields = [ field for field in self._all_fields if field not in self._auto_inc_fields ] sdata = { 'fields': ','.join(fields), 'values': ','.join(['%s'] * len(fields)) } sdata.update(self._meta) sql = """INSERT INTO %(table_name)s (%(fields)s) VALUES (%(values)s)""" % sdata with self._env.db_transaction as db: cursor = db.cursor() cursor.execute(sql, [self._data[f] for f in fields]) for auto_in_field in self._auto_inc_fields: self._data[auto_in_field] = db.get_last_id( cursor, sdata["table_name"], auto_in_field) self._exists = True self._old_data.update(self._data) TicketSystem(self._env).reset_ticket_fields() ResourceSystem(self._env).resource_created(self)
def resource_exists(env, resource): """Checks for resource existence without actually instantiating a model. :return: `True` if the resource exists, `False` if it doesn't and `None` in case no conclusion could be made (i.e. when `IResourceManager.resource_exists` is not implemented). >>> from trac.test import EnvironmentStub >>> env = EnvironmentStub() >>> resource_exists(env, Resource('dummy-realm', 'dummy-id')) is None True >>> resource_exists(env, Resource('dummy-realm')) False """ manager = ResourceSystem(env).get_resource_manager(resource.realm) if manager and hasattr(manager, 'resource_exists'): return manager.resource_exists(resource) elif resource.id is None: return False
def delete(self, version=None, db=None): """Delete one or all versions of a page. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ if not self.exists: raise TracError(_("Cannot delete non-existent page")) with self.env.db_transaction as db: if version is None: # Delete a wiki page completely db("DELETE FROM wiki WHERE name=%s", (self.name, )) self.env.log.info("Deleted page %s", self.name) else: # Delete only a specific page version db("DELETE FROM wiki WHERE name=%s and version=%s", (self.name, version)) self.env.log.info("Deleted version %d of page %s", version, self.name) if version is None or version == self.version: self._fetch(self.name, None) if not self.exists: # Invalidate page name cache del WikiSystem(self.env).pages # Delete orphaned attachments from trac.attachment import Attachment Attachment.delete_all(self.env, 'wiki', self.name) # Let change listeners know about the deletion if not self.exists: for listener in WikiSystem(self.env).change_listeners: listener.wiki_page_deleted(self) ResourceSystem(self.env).resource_deleted(self) else: for listener in WikiSystem(self.env).change_listeners: if hasattr(listener, 'wiki_page_version_deleted'): listener.wiki_page_version_deleted(self) ResourceSystem(self.env).resource_version_deleted(self)
def _get_helppage_link(self, req): link = realm = resource_id = None if self.helppage_opt.startswith('/'): # Assume valid URL to arbitrary resource inside # of the current Trac environment. link = req.href(self.helppage_opt) if not link and ':' in self.helppage_opt: realm, resource_id = self.helppage_opt.split(':', 1) # Validate realm-like prefix against resource realm list, # but exclude 'wiki' to allow deferred page creation. rsys = ResourceSystem(self.env) if realm in set(rsys.get_known_realms()) - set('wiki'): mgr = rsys.get_resource_manager(realm) # Handle optional IResourceManager method gracefully. try: if mgr.resource_exists(Resource(realm, resource_id)): link = mgr.get_resource_url(resource_id, req.href) except AttributeError: # Assume generic resource URL build rule. link = req.href(realm, resource_id) if not link: if not resource_id: # Assume wiki page name for backwards-compatibility. resource_id = self.helppage_opt # Preserve anchor without 'path_safe' arg (since Trac 0.12.2dev). if '#' in resource_id: path, anchor = resource_id.split('#', 1) else: anchor = None path = resource_id if hasattr(unicode_quote_plus, "safe"): # Use method for query string quoting (since Trac 0.13dev). anchor = unicode_quote_plus(anchor, safe="?!~*'()") else: anchor = unicode_quote_plus(anchor) link = '#'.join([req.href.wiki(path), anchor]) return link
def delete(self, db=None): """Delete the ticket. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ with self.env.db_transaction as db: Attachment.delete_all(self.env, 'ticket', self.id, db) db("DELETE FROM ticket WHERE id=%s", (self.id, )) db("DELETE FROM ticket_change WHERE ticket=%s", (self.id, )) db("DELETE FROM ticket_custom WHERE ticket=%s", (self.id, )) for listener in TicketSystem(self.env).change_listeners: listener.ticket_deleted(self) ResourceSystem(self.env).resource_deleted(self)
def delete(self, db=None): """Delete the component. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert self.exists, "Cannot delete non-existent component" with self.env.db_transaction as db: self.env.log.info("Deleting component %s", self.name) db("DELETE FROM component WHERE name=%s", (self.name, )) TicketSystem(self.env).reset_ticket_fields() ResourceSystem(self.env).resource_deleted(self) self.name = self._old_name = None
def delete(self): """Deletes the matching record from the database""" if not self._exists: raise TracError('%(object_name)s does not exist' % self._meta) where, values = fields_to_kv_str(self._env, self._key_fields, self._data) sdata = {'where': where} sdata.update(self._meta) sql = """DELETE FROM %(table_name)s WHERE %(where)s""" % sdata with self._env.db_transaction as db: db(sql, values) self._exists = False TicketSystem(self._env).reset_ticket_fields() ResourceSystem(self._env).resource_deleted(self) self._data = dict([(k, None) for k in self._data.keys()]) self._old_data.update(self._data)
def get_resource_description(self, resource, format=None, context=None, **kwargs): nbhprefix = ResourceSystem(self.env).neighborhood_prefix( resource.neighborhood) if format == 'compact': return '%s#%s' % (nbhprefix, resource.id) elif format == 'summary': from trac.ticket.model import Ticket ticket = Ticket(self.env, resource.id) args = [ ticket[f] for f in ('summary', 'status', 'resolution', 'type') ] return self.format_summary(*args) return nbhprefix + _("Ticket #%(shortname)s", shortname=resource.id)
def resource_from_path(env, path): """Find realm and resource ID from resource URL. Assuming simple resource paths to convert to Trac resource identifiers. """ if isinstance(path, basestring): path = path.strip('/') # Special-case: Default TracWiki start page. if path == 'wiki': path += '/WikiStart' for realm in ResourceSystem(env).get_known_realms(): if path.startswith(realm): resource_id = re.sub(realm, '', path, 1).lstrip('/') resource = Resource(realm, resource_id) if not resource_check: return resource elif resource_exists(env, resource) in (None, True): return get_versioned_resource(env, resource)
def insert(self, db=None): """Insert a new version. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert not self.exists, "Cannot insert existing version" self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid version name.")) with self.env.db_transaction as db: self.env.log.debug("Creating new version '%s'", self.name) db("INSERT INTO version (name,time,description) VALUES (%s,%s,%s)", (self.name, to_utimestamp(self.time), self.description)) self._old_name = self.name TicketSystem(self.env).reset_ticket_fields() ResourceSystem(self.env).resource_created(self)
def update(self, db=None): """Update the milestone. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid milestone name.")) old = self._old.copy() with self.env.db_transaction as db: old_name = old['name'] self.env.log.info("Updating milestone '%s'", self.name) db( """UPDATE milestone SET name=%s, due=%s, completed=%s, description=%s WHERE name=%s """, (self.name, to_utimestamp(self.due), to_utimestamp(self.completed), self.description, old_name)) self.checkin() if self.name != old_name: # Update milestone field in tickets self.env.log.info( "Updating milestone field of all tickets " "associated with milestone '%s'", self.name) db("UPDATE ticket SET milestone=%s WHERE milestone=%s", (self.name, old_name)) TicketSystem(self.env).reset_ticket_fields() # Reparent attachments Attachment.reparent_all(self.env, 'milestone', old_name, 'milestone', self.name) old_values = dict( (k, v) for k, v in old.iteritems() if getattr(self, k) != v) for listener in TicketSystem(self.env).milestone_change_listeners: listener.milestone_changed(self, old_values) ResourceSystem(self.env).resource_changed(self, old_values)
def insert(self, db=None): """Insert a new milestone. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ self.name = simplify_whitespace(self.name) if not self.name: raise TracError(_("Invalid milestone name.")) with self.env.db_transaction as db: self.env.log.debug("Creating new milestone '%s'", self.name) db( """INSERT INTO milestone (name, due, completed, description) VALUES (%s,%s,%s,%s) """, (self.name, to_utimestamp(self.due), to_utimestamp(self.completed), self.description)) self.checkin() TicketSystem(self.env).reset_ticket_fields() for listener in TicketSystem(self.env).milestone_change_listeners: listener.milestone_created(self) ResourceSystem(self.env).resource_created(self)
def insert(self, when=None, db=None): """Add ticket to database. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ assert not self.exists, 'Cannot insert an existing ticket' if 'cc' in self.values: self['cc'] = _fixup_cc_list(self.values['cc']) # Add a timestamp if when is None: when = datetime.now(utc) self.values['time'] = self.values['changetime'] = when # The owner field defaults to the component owner if self.values.get('owner') == '< default >': default_to_owner = '' if self.values.get('component'): try: component = Component(self.env, self['component']) default_to_owner = component.owner # even if it's empty except ResourceNotFound: # No such component exists pass # If the current owner is "< default >", we need to set it to # _something_ else, even if that something else is blank. self['owner'] = default_to_owner # Perform type conversions values = dict(self.values) for field in self.time_fields: if field in values: values[field] = to_utimestamp(values[field]) # Insert ticket record std_fields = [] custom_fields = [] for f in self.fields: fname = f['name'] if fname in self.values: if f.get('custom'): custom_fields.append(fname) else: std_fields.append(fname) with self.env.db_transaction as db: cursor = db.cursor() cursor.execute( "INSERT INTO ticket (%s) VALUES (%s)" % (','.join(std_fields), ','.join(['%s'] * len(std_fields))), [values[name] for name in std_fields]) tkt_id = db.get_last_id(cursor, 'ticket') # Insert custom fields if custom_fields: db.executemany( """INSERT INTO ticket_custom (ticket, name, value) VALUES (%s, %s, %s) """, [(tkt_id, c, self[c]) for c in custom_fields]) self.id = tkt_id self.resource = self.resource(id=tkt_id) self._old = {} for listener in TicketSystem(self.env).change_listeners: listener.ticket_created(self) ResourceSystem(self.env).resource_created(self) return self.id
def save_changes(self, author=None, comment=None, when=None, db=None, cnum='', replyto=None): """ Store ticket changes in the database. The ticket must already exist in the database. Returns False if there were no changes to save, True otherwise. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 :since 1.0: the `cnum` parameter is deprecated, and threading should be controlled with the `replyto` argument """ assert self.exists, "Cannot update a new ticket" if 'cc' in self.values: self['cc'] = _fixup_cc_list(self.values['cc']) props_unchanged = all( self.values.get(k) == v for k, v in self._old.iteritems()) if (not comment or not comment.strip()) and props_unchanged: return False # Not modified if when is None: when = datetime.now(utc) when_ts = to_utimestamp(when) if 'component' in self.values: # If the component is changed on a 'new' ticket # then owner field is updated accordingly. (#623). if self.values.get('status') == 'new' \ and 'component' in self._old \ and 'owner' not in self._old: try: old_comp = Component(self.env, self._old['component']) old_owner = old_comp.owner or '' current_owner = self.values.get('owner') or '' if old_owner == current_owner: new_comp = Component(self.env, self['component']) if new_comp.owner: self['owner'] = new_comp.owner except TracError: # If the old component has been removed from the database # we just leave the owner as is. pass with self.env.db_transaction as db: db("UPDATE ticket SET changetime=%s WHERE id=%s", (when_ts, self.id)) # find cnum if it isn't provided if not cnum: num = 0 for ts, old in db( """ SELECT DISTINCT tc1.time, COALESCE(tc2.oldvalue,'') FROM ticket_change AS tc1 LEFT OUTER JOIN ticket_change AS tc2 ON tc2.ticket=%s AND tc2.time=tc1.time AND tc2.field='comment' WHERE tc1.ticket=%s ORDER BY tc1.time DESC """, (self.id, self.id)): # Use oldvalue if available, else count edits try: num += int(old.rsplit('.', 1)[-1]) break except ValueError: num += 1 cnum = str(num + 1) if replyto: cnum = '%s.%s' % (replyto, cnum) # store fields for name in self._old.keys(): if name in self.custom_fields: for row in db( """SELECT * FROM ticket_custom WHERE ticket=%s and name=%s """, (self.id, name)): db( """UPDATE ticket_custom SET value=%s WHERE ticket=%s AND name=%s """, (self[name], self.id, name)) break else: db( """INSERT INTO ticket_custom (ticket,name,value) VALUES(%s,%s,%s) """, (self.id, name, self[name])) else: db("UPDATE ticket SET %s=%%s WHERE id=%%s" % name, (self[name], self.id)) db( """INSERT INTO ticket_change (ticket,time,author,field,oldvalue,newvalue) VALUES (%s, %s, %s, %s, %s, %s) """, (self.id, when_ts, author, name, self._old[name], self[name])) # always save comment, even if empty # (numbering support for timeline) db( """INSERT INTO ticket_change (ticket,time,author,field,oldvalue,newvalue) VALUES (%s,%s,%s,'comment',%s,%s) """, (self.id, when_ts, author, cnum, comment)) old_values = self._old self._old = {} self.values['changetime'] = when for listener in TicketSystem(self.env).change_listeners: listener.ticket_changed(self, comment, author, old_values) context = dict(comment=comment, author=author) ResourceSystem(self.env).resource_changed(self, old_values, context) return int(cnum.rsplit('.', 1)[-1])
def save(self, author, comment, remote_addr, t=None, db=None): """Save a new version of a page. :since 1.0: the `db` parameter is no longer needed and will be removed in version 1.1.1 """ if not validate_page_name(self.name): raise TracError( _("Invalid Wiki page name '%(name)s'", name=self.name)) new_text = self.text != self.old_text if not new_text and self.readonly == self.old_readonly: raise TracError(_("Page not modified")) t = t or datetime.now(utc) with self.env.db_transaction as db: if new_text: db( """INSERT INTO wiki (name, version, time, author, ipnr, text, comment, readonly) VALUES (%s,%s,%s,%s,%s,%s,%s,%s) """, (self.name, self.version + 1, to_utimestamp(t), author, remote_addr, self.text, comment, self.readonly)) self.version += 1 self.resource = self.resource(version=self.version) else: db("UPDATE wiki SET readonly=%s WHERE name=%s", (self.readonly, self.name)) if self.version == 1: # Invalidate page name cache del WikiSystem(self.env).pages self.author = author self.comment = comment self.time = t for listener in WikiSystem(self.env).change_listeners: if self.version == 1: listener.wiki_page_added(self) else: listener.wiki_page_changed(self, self.version, t, comment, author, remote_addr) context = dict(version=self.version, time=t, comment=comment, author=author, remote_addr=remote_addr) if self.version == 1: ResourceSystem(self.env).resource_created(self, context) else: old_values = dict() if self.readonly != self.old_readonly: old_values["readonly"] = self.old_readonly if self.text != self.old_text: old_values["text"] = self.old_text ResourceSystem(self.env).resource_changed(self, old_values, context) self.old_readonly = self.readonly self.old_text = self.text