Server : Apache System : Linux iad1-shared-b8-43 6.6.49-grsec-jammy+ #10 SMP Thu Sep 12 23:23:08 UTC 2024 x86_64 User : dh_edsupp ( 6597262) PHP Version : 8.2.26 Disable Function : NONE Directory : /lib/python3/dist-packages/trac/wiki/ |
Upload File : |
# -*- coding: utf-8 -*- # # Copyright (C) 2003-2021 Edgewall Software # Copyright (C) 2003-2005 Jonas Borgström <jonas@edgewall.com> # Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de> # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://trac.edgewall.org/wiki/TracLicense. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at https://trac.edgewall.org/log/. # # Author: Jonas Borgström <jonas@edgewall.com> # Christopher Lenz <cmlenz@gmx.de> from trac.core import * from trac.resource import Resource from trac.util.datefmt import datetime_now, from_utimestamp, to_utimestamp, utc from trac.util.translation import _ from trac.wiki.api import WikiSystem, validate_page_name class WikiPage(object): """Represents a wiki page (new or existing).""" realm = WikiSystem.realm @property def resource(self): return Resource(self.realm, self.name, self._resource_version) def __init__(self, env, name=None, version=None): """Create a new page object or retrieves an existing page. :param env: an `Environment` object. :param name: the page name or a `Resource` object. :param version: the page version. The value takes precedence over the `Resource` version when both are specified. """ self.env = env if version: try: version = int(version) except ValueError: version = None if isinstance(name, Resource): resource = name name = resource.id if version is None and resource.version is not None: try: version = int(resource.version) except ValueError: version = None self.name = name # The version attribute always returns the version of the page, # however resource.version will be None when version hasn't been # specified when creating the object and the object represents the # most recent version of the page. This behavior is used in web_ui.py # to determine whether to render a versioned page, or just the most # recent version of the page. self._resource_version = version if name: self._fetch(name, version) else: self.version = 0 self.text = self.comment = self.author = '' self.time = None self.readonly = 0 self.old_text = self.text self.old_readonly = self.readonly def _fetch(self, name, version=None): if version is not None: sql = """SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s AND version=%s""" args = (name, int(version)) else: sql = """SELECT version, time, author, text, comment, readonly FROM wiki WHERE name=%s ORDER BY version DESC LIMIT 1""" args = (name,) for version, time, author, text, comment, readonly in \ self.env.db_query(sql, args): self.version = int(version) self.author = author self.time = from_utimestamp(time) self.text = text self.comment = comment self.readonly = int(readonly) if readonly else 0 break else: self.version = 0 self.text = self.comment = self.author = '' self.time = None self.readonly = 0 def __repr__(self): if self.name is None: name = self.name else: name = '%s@%s' % (self.name, self.version) return '<%s %r>' % (self.__class__.__name__, name) exists = property(lambda self: self.version > 0) def delete(self, version=None): """Delete one or all versions of a page. """ 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, self.realm, 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) else: for listener in WikiSystem(self.env).change_listeners: if hasattr(listener, 'wiki_page_version_deleted'): listener.wiki_page_version_deleted(self) def save(self, author, comment, t=None, replace=False): """Save a new version of a page.""" 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: if replace and self.version != 0: db(""" UPDATE wiki SET text=%s WHERE name=%s AND version=%s """, (self.text, self.name, self.version)) else: self.version += 1 db("""INSERT INTO wiki (name,version,time,author,text,comment,readonly) VALUES (%s,%s,%s,%s,%s,%s,%s) """, (self.name, self.version, to_utimestamp(t), author, self.text, comment, self.readonly)) 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: with self.env.component_guard(listener): if self.version == 1: listener.wiki_page_added(self) else: listener.wiki_page_changed(self, self.version, t, comment, author) self.old_readonly = self.readonly self.old_text = self.text 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 literally doesn't exist anymore. """ if not self.exists: raise TracError(_("Cannot rename non-existent page")) if not new_name: raise TracError(_("A new name is mandatory for a rename.")) if self.name == new_name: raise TracError(_("Page name is unchanged.")) 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(_("The page '%(name)s' already exists.", 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, self.realm, old_name, self.realm, 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) def edit_comment(self, new_comment): """Edit comment of wiki page version in-place.""" if not self.exists: raise TracError(_("Cannot edit comment of non-existent page")) old_comment = self.comment with self.env.db_transaction as db: db("UPDATE wiki SET comment=%s WHERE name=%s AND version=%s", (new_comment, self.name, self.version)) self.comment = new_comment self.env.log.info("Changed comment on page %s version %s to %s", self.name, self.version, new_comment) for listener in WikiSystem(self.env).change_listeners: if hasattr(listener, 'wiki_page_comment_modified'): listener.wiki_page_comment_modified(self, old_comment) def get_history(self): """Retrieve the edit history of a wiki page. :return: a tuple containing the `version`, `datetime`, `author` and `comment`. """ for version, ts, author, comment in self.env.db_query(""" SELECT version, time, author, comment FROM wiki WHERE name=%s AND version<=%s ORDER BY version DESC """, (self.name, self.version)): yield version, from_utimestamp(ts), author, comment