Package trac :: Package wiki :: Module model

Source Code for Module trac.wiki.model

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (C) 2003-2020 Edgewall Software 
  4  # Copyright (C) 2003-2005 Jonas Borgström <[email protected]> 
  5  # Copyright (C) 2005 Christopher Lenz <[email protected]> 
  6  # All rights reserved. 
  7  # 
  8  # This software is licensed as described in the file COPYING, which 
  9  # you should have received as part of this distribution. The terms 
 10  # are also available at https://trac.edgewall.org/wiki/TracLicense. 
 11  # 
 12  # This software consists of voluntary contributions made by many 
 13  # individuals. For the exact contribution history, see the revision 
 14  # history and logs, available at https://trac.edgewall.org/log/. 
 15  # 
 16  # Author: Jonas Borgström <[email protected]> 
 17  #         Christopher Lenz <[email protected]> 
 18   
 19  from __future__ import with_statement 
 20   
 21  from trac.core import * 
 22  from trac.resource import Resource 
 23  from trac.util.datefmt import datetime_now, from_utimestamp, to_utimestamp, utc 
 24  from trac.util.translation import _ 
 25  from trac.wiki.api import WikiSystem, validate_page_name 
 26   
 27   
28 -class WikiPage(object):
29 """Represents a wiki page (new or existing). 30 31 :since 1.0.3: the `ipnr` is deprecated and will be removed in 1.3.1 32 """ 33 34 realm = 'wiki' 35
36 - def __init__(self, env, name=None, version=None, db=None):
37 self.env = env 38 if isinstance(name, Resource): 39 self.resource = name 40 name = self.resource.id 41 else: 42 if version: 43 version = int(version) # must be a number or None 44 self.resource = Resource('wiki', name, version) 45 self.name = name 46 if name: 47 self._fetch(name, version, db) 48 else: 49 self.version = 0 50 self.text = self.comment = self.author = '' 51 self.time = None 52 self.readonly = 0 53 self.old_text = self.text 54 self.old_readonly = self.readonly
55
56 - def _fetch(self, name, version=None, db=None):
57 if version is not None: 58 sql = """SELECT version, time, author, text, comment, readonly 59 FROM wiki WHERE name=%s AND version=%s""" 60 args = (name, int(version)) 61 else: 62 sql = """SELECT version, time, author, text, comment, readonly 63 FROM wiki WHERE name=%s ORDER BY version DESC LIMIT 1""" 64 args = (name,) 65 for version, time, author, text, comment, readonly in \ 66 self.env.db_query(sql, args): 67 self.version = int(version) 68 self.author = author 69 self.time = from_utimestamp(time) 70 self.text = text 71 self.comment = comment 72 self.readonly = int(readonly) if readonly else 0 73 break 74 else: 75 self.version = 0 76 self.text = self.comment = self.author = '' 77 self.time = None 78 self.readonly = 0
79 80 exists = property(lambda self: self.version > 0) 81
82 - def delete(self, version=None, db=None):
83 """Delete one or all versions of a page. 84 85 :since 1.0: the `db` parameter is no longer needed and will be removed 86 in version 1.1.1 87 """ 88 if not self.exists: 89 raise TracError(_("Cannot delete non-existent page")) 90 91 with self.env.db_transaction as db: 92 if version is None: 93 # Delete a wiki page completely 94 db("DELETE FROM wiki WHERE name=%s", (self.name,)) 95 self.env.log.info("Deleted page %s", self.name) 96 else: 97 # Delete only a specific page version 98 db("DELETE FROM wiki WHERE name=%s and version=%s", 99 (self.name, version)) 100 self.env.log.info("Deleted version %d of page %s", version, 101 self.name) 102 103 if version is None or version == self.version: 104 self._fetch(self.name, None) 105 106 if not self.exists: 107 # Invalidate page name cache 108 del WikiSystem(self.env).pages 109 # Delete orphaned attachments 110 from trac.attachment import Attachment 111 Attachment.delete_all(self.env, 'wiki', self.name) 112 113 # Let change listeners know about the deletion 114 if not self.exists: 115 for listener in WikiSystem(self.env).change_listeners: 116 listener.wiki_page_deleted(self) 117 else: 118 for listener in WikiSystem(self.env).change_listeners: 119 if hasattr(listener, 'wiki_page_version_deleted'): 120 listener.wiki_page_version_deleted(self)
121
122 - def save(self, author, comment, remote_addr=None, t=None, db=None):
123 """Save a new version of a page. 124 125 :since 1.0: the `db` parameter is no longer needed and will be removed 126 in version 1.1.1 127 :since 1.0.3: `remote_addr` is optional and deprecated, and will be 128 removed in 1.3.1 129 """ 130 if not validate_page_name(self.name): 131 raise TracError(_("Invalid Wiki page name '%(name)s'", 132 name=self.name)) 133 134 new_text = self.text != self.old_text 135 if not new_text and self.readonly == self.old_readonly: 136 raise TracError(_("Page not modified")) 137 t = t or datetime_now(utc) 138 139 with self.env.db_transaction as db: 140 if new_text: 141 db("""INSERT INTO wiki (name, version, time, author, ipnr, 142 text, comment, readonly) 143 VALUES (%s,%s,%s,%s,%s,%s,%s,%s) 144 """, (self.name, self.version + 1, to_utimestamp(t), 145 author, remote_addr, self.text, comment, 146 self.readonly)) 147 self.version += 1 148 self.resource = self.resource(version=self.version) 149 else: 150 db("UPDATE wiki SET readonly=%s WHERE name=%s", 151 (self.readonly, self.name)) 152 if self.version == 1: 153 # Invalidate page name cache 154 del WikiSystem(self.env).pages 155 156 self.author = author 157 self.comment = comment 158 self.time = t 159 160 for listener in WikiSystem(self.env).change_listeners: 161 if self.version == 1: 162 listener.wiki_page_added(self) 163 else: 164 from trac.util import arity 165 if arity(listener.wiki_page_changed) == 6: 166 listener.wiki_page_changed(self, self.version, t, 167 comment, author, remote_addr) 168 else: 169 listener.wiki_page_changed(self, self.version, t, 170 comment, author) 171 172 self.old_readonly = self.readonly 173 self.old_text = self.text
174
175 - def rename(self, new_name):
176 """Rename wiki page in-place, keeping the history intact. 177 Renaming a page this way will eventually leave dangling references 178 to the old page - which literally doesn't exist anymore. 179 """ 180 if not self.exists: 181 raise TracError(_("Cannot rename non-existent page")) 182 183 if not validate_page_name(new_name): 184 raise TracError(_("Invalid Wiki page name '%(name)s'", 185 name=new_name)) 186 old_name = self.name 187 188 with self.env.db_transaction as db: 189 new_page = WikiPage(self.env, new_name) 190 if new_page.exists: 191 raise TracError(_("Can't rename to existing %(name)s page.", 192 name=new_name)) 193 194 db("UPDATE wiki SET name=%s WHERE name=%s", (new_name, old_name)) 195 # Invalidate page name cache 196 del WikiSystem(self.env).pages 197 # Reparent attachments 198 from trac.attachment import Attachment 199 Attachment.reparent_all(self.env, 'wiki', old_name, 'wiki', 200 new_name) 201 202 self.name = self.resource.id = new_name 203 self.env.log.info("Renamed page %s to %s", old_name, new_name) 204 205 for listener in WikiSystem(self.env).change_listeners: 206 if hasattr(listener, 'wiki_page_renamed'): 207 listener.wiki_page_renamed(self, old_name)
208
209 - def get_history(self, db=None):
210 """Retrieve the edit history of a wiki page. 211 212 :return: a tuple containing the `version`, `datetime`, `author`, 213 `comment` and `ipnr`. 214 :since 1.0: the `db` parameter is no longer needed and will be removed 215 in version 1.1.1 216 :since 1.0.3: use of `ipnr` is deprecated and will be removed in 1.3.1 217 """ 218 for version, ts, author, comment, ipnr in self.env.db_query(""" 219 SELECT version, time, author, comment, ipnr FROM wiki 220 WHERE name=%s AND version<=%s ORDER BY version DESC 221 """, (self.name, self.version)): 222 yield version, from_utimestamp(ts), author, comment, ipnr
223