paul@0 | 1 | # -*- coding: iso-8859-1 -*- |
paul@0 | 2 | """ |
paul@0 | 3 | MoinMoin - MoinSupport library (derived from EventAggregatorSupport) |
paul@0 | 4 | |
paul@0 | 5 | @copyright: 2008, 2009, 2010, 2011, 2012 by Paul Boddie <paul@boddie.org.uk> |
paul@0 | 6 | @copyright: 2000-2004 Juergen Hermann <jh@web.de>, |
paul@0 | 7 | 2005-2008 MoinMoin:ThomasWaldmann. |
paul@0 | 8 | @license: GNU GPL (v2 or later), see COPYING.txt for details. |
paul@0 | 9 | """ |
paul@0 | 10 | |
paul@0 | 11 | from DateSupport import * |
paul@1 | 12 | from MoinMoin.Page import Page |
paul@0 | 13 | from MoinMoin import wikiutil |
paul@0 | 14 | import re |
paul@0 | 15 | import time |
paul@0 | 16 | |
paul@0 | 17 | __version__ = "0.1" |
paul@0 | 18 | |
paul@0 | 19 | # Content type parsing. |
paul@0 | 20 | |
paul@0 | 21 | encoding_regexp_str = ur'(?P<content_type>[^\s;]*)(?:;\s*charset=(?P<encoding>[-A-Za-z0-9]+))?' |
paul@0 | 22 | encoding_regexp = re.compile(encoding_regexp_str) |
paul@0 | 23 | |
paul@0 | 24 | # Utility functions. |
paul@0 | 25 | |
paul@0 | 26 | def getContentTypeAndEncoding(content_type): |
paul@0 | 27 | m = encoding_regexp.search(content_type) |
paul@0 | 28 | if m: |
paul@0 | 29 | return m.group("content_type"), m.group("encoding") |
paul@0 | 30 | else: |
paul@0 | 31 | return None, None |
paul@0 | 32 | |
paul@0 | 33 | def int_or_none(x): |
paul@0 | 34 | if x is None: |
paul@0 | 35 | return x |
paul@0 | 36 | else: |
paul@0 | 37 | return int(x) |
paul@0 | 38 | |
paul@0 | 39 | # Utility classes and associated functions. |
paul@0 | 40 | |
paul@0 | 41 | class Form: |
paul@0 | 42 | |
paul@0 | 43 | """ |
paul@0 | 44 | A wrapper preserving MoinMoin 1.8.x (and earlier) behaviour in a 1.9.x |
paul@0 | 45 | environment. |
paul@0 | 46 | """ |
paul@0 | 47 | |
paul@0 | 48 | def __init__(self, form): |
paul@0 | 49 | self.form = form |
paul@0 | 50 | |
paul@0 | 51 | def has_key(self, name): |
paul@0 | 52 | return not not self.form.getlist(name) |
paul@0 | 53 | |
paul@0 | 54 | def get(self, name, default=None): |
paul@0 | 55 | values = self.form.getlist(name) |
paul@0 | 56 | if not values: |
paul@0 | 57 | return default |
paul@0 | 58 | else: |
paul@0 | 59 | return values |
paul@0 | 60 | |
paul@0 | 61 | def __getitem__(self, name): |
paul@0 | 62 | return self.form.getlist(name) |
paul@0 | 63 | |
paul@0 | 64 | class ActionSupport: |
paul@0 | 65 | |
paul@0 | 66 | """ |
paul@0 | 67 | Work around disruptive MoinMoin changes in 1.9, and also provide useful |
paul@0 | 68 | convenience methods. |
paul@0 | 69 | """ |
paul@0 | 70 | |
paul@0 | 71 | def get_form(self): |
paul@0 | 72 | return get_form(self.request) |
paul@0 | 73 | |
paul@0 | 74 | def _get_selected(self, value, input_value): |
paul@0 | 75 | |
paul@0 | 76 | """ |
paul@0 | 77 | Return the HTML attribute text indicating selection of an option (or |
paul@0 | 78 | otherwise) if 'value' matches 'input_value'. |
paul@0 | 79 | """ |
paul@0 | 80 | |
paul@0 | 81 | return input_value is not None and value == input_value and 'selected="selected"' or '' |
paul@0 | 82 | |
paul@0 | 83 | def _get_selected_for_list(self, value, input_values): |
paul@0 | 84 | |
paul@0 | 85 | """ |
paul@0 | 86 | Return the HTML attribute text indicating selection of an option (or |
paul@0 | 87 | otherwise) if 'value' matches one of the 'input_values'. |
paul@0 | 88 | """ |
paul@0 | 89 | |
paul@0 | 90 | return value in input_values and 'selected="selected"' or '' |
paul@0 | 91 | |
paul@0 | 92 | def _get_input(self, form, name, default=None): |
paul@0 | 93 | |
paul@0 | 94 | """ |
paul@0 | 95 | Return the input from 'form' having the given 'name', returning either |
paul@0 | 96 | the input converted to an integer or the given 'default' (optional, None |
paul@0 | 97 | if not specified). |
paul@0 | 98 | """ |
paul@0 | 99 | |
paul@0 | 100 | value = form.get(name, [None])[0] |
paul@0 | 101 | if not value: # true if 0 obtained |
paul@0 | 102 | return default |
paul@0 | 103 | else: |
paul@0 | 104 | return int(value) |
paul@0 | 105 | |
paul@0 | 106 | def get_form(request): |
paul@0 | 107 | |
paul@0 | 108 | "Work around disruptive MoinMoin changes in 1.9." |
paul@0 | 109 | |
paul@0 | 110 | if hasattr(request, "values"): |
paul@0 | 111 | return Form(request.values) |
paul@0 | 112 | else: |
paul@0 | 113 | return request.form |
paul@0 | 114 | |
paul@0 | 115 | class send_headers_cls: |
paul@0 | 116 | |
paul@0 | 117 | """ |
paul@0 | 118 | A wrapper to preserve MoinMoin 1.8.x (and earlier) request behaviour in a |
paul@0 | 119 | 1.9.x environment. |
paul@0 | 120 | """ |
paul@0 | 121 | |
paul@0 | 122 | def __init__(self, request): |
paul@0 | 123 | self.request = request |
paul@0 | 124 | |
paul@0 | 125 | def __call__(self, headers): |
paul@0 | 126 | for header in headers: |
paul@0 | 127 | parts = header.split(":") |
paul@0 | 128 | self.request.headers.add(parts[0], ":".join(parts[1:])) |
paul@0 | 129 | |
paul@0 | 130 | def get_send_headers(request): |
paul@0 | 131 | |
paul@0 | 132 | "Return a function that can send response headers." |
paul@0 | 133 | |
paul@0 | 134 | if hasattr(request, "http_headers"): |
paul@0 | 135 | return request.http_headers |
paul@0 | 136 | elif hasattr(request, "emit_http_headers"): |
paul@0 | 137 | return request.emit_http_headers |
paul@0 | 138 | else: |
paul@0 | 139 | return send_headers_cls(request) |
paul@0 | 140 | |
paul@0 | 141 | def escattr(s): |
paul@0 | 142 | return wikiutil.escape(s, 1) |
paul@0 | 143 | |
paul@0 | 144 | def getPathInfo(request): |
paul@0 | 145 | if hasattr(request, "getPathinfo"): |
paul@0 | 146 | return request.getPathinfo() |
paul@0 | 147 | else: |
paul@0 | 148 | return request.path |
paul@0 | 149 | |
paul@1 | 150 | # Page access functions. |
paul@1 | 151 | |
paul@1 | 152 | def getPageURL(page): |
paul@1 | 153 | |
paul@1 | 154 | "Return the URL of the given 'page'." |
paul@1 | 155 | |
paul@1 | 156 | request = page.request |
paul@1 | 157 | return request.getQualifiedURL(page.url(request, relative=0)) |
paul@1 | 158 | |
paul@1 | 159 | def getFormat(page): |
paul@1 | 160 | |
paul@1 | 161 | "Get the format used on the given 'page'." |
paul@1 | 162 | |
paul@1 | 163 | return page.pi["format"] |
paul@1 | 164 | |
paul@1 | 165 | def getMetadata(page): |
paul@1 | 166 | |
paul@1 | 167 | """ |
paul@1 | 168 | Return a dictionary containing items describing for the given 'page' the |
paul@1 | 169 | page's "created" time, "last-modified" time, "sequence" (or revision number) |
paul@1 | 170 | and the "last-comment" made about the last edit. |
paul@1 | 171 | """ |
paul@1 | 172 | |
paul@1 | 173 | request = page.request |
paul@1 | 174 | |
paul@1 | 175 | # Get the initial revision of the page. |
paul@1 | 176 | |
paul@1 | 177 | revisions = page.getRevList() |
paul@1 | 178 | event_page_initial = Page(request, page.page_name, rev=revisions[-1]) |
paul@1 | 179 | |
paul@1 | 180 | # Get the created and last modified times. |
paul@1 | 181 | |
paul@1 | 182 | initial_revision = getPageRevision(event_page_initial) |
paul@1 | 183 | |
paul@1 | 184 | metadata = {} |
paul@1 | 185 | metadata["created"] = initial_revision["timestamp"] |
paul@1 | 186 | latest_revision = getPageRevision(page) |
paul@1 | 187 | metadata["last-modified"] = latest_revision["timestamp"] |
paul@1 | 188 | metadata["sequence"] = len(revisions) - 1 |
paul@1 | 189 | metadata["last-comment"] = latest_revision["comment"] |
paul@1 | 190 | |
paul@1 | 191 | return metadata |
paul@0 | 192 | |
paul@0 | 193 | def getPageRevision(page): |
paul@0 | 194 | |
paul@0 | 195 | "Return the revision details dictionary for the given 'page'." |
paul@0 | 196 | |
paul@0 | 197 | # From Page.edit_info... |
paul@0 | 198 | |
paul@0 | 199 | if hasattr(page, "editlog_entry"): |
paul@0 | 200 | line = page.editlog_entry() |
paul@0 | 201 | else: |
paul@0 | 202 | line = page._last_edited(page.request) # MoinMoin 1.5.x and 1.6.x |
paul@0 | 203 | |
paul@0 | 204 | # Similar to Page.mtime_usecs behaviour... |
paul@0 | 205 | |
paul@0 | 206 | if line: |
paul@0 | 207 | timestamp = line.ed_time_usecs |
paul@0 | 208 | mtime = wikiutil.version2timestamp(long(timestamp)) # must be long for py 2.2.x |
paul@0 | 209 | comment = line.comment |
paul@0 | 210 | else: |
paul@0 | 211 | mtime = 0 |
paul@0 | 212 | comment = "" |
paul@0 | 213 | |
paul@0 | 214 | # Leave the time zone empty. |
paul@0 | 215 | |
paul@0 | 216 | return {"timestamp" : DateTime(time.gmtime(mtime)[:6] + (None,)), "comment" : comment} |
paul@0 | 217 | |
paul@0 | 218 | # User interface functions. |
paul@0 | 219 | |
paul@0 | 220 | def getParameter(request, name, default=None): |
paul@0 | 221 | |
paul@0 | 222 | """ |
paul@0 | 223 | Using the given 'request', return the value of the parameter with the given |
paul@0 | 224 | 'name', returning the optional 'default' (or None) if no value was supplied |
paul@0 | 225 | in the 'request'. |
paul@0 | 226 | """ |
paul@0 | 227 | |
paul@0 | 228 | return get_form(request).get(name, [default])[0] |
paul@0 | 229 | |
paul@0 | 230 | def getQualifiedParameter(request, prefix, argname, default=None): |
paul@0 | 231 | |
paul@0 | 232 | """ |
paul@0 | 233 | Using the given 'request', 'prefix' and 'argname', retrieve the value of the |
paul@0 | 234 | qualified parameter, returning the optional 'default' (or None) if no value |
paul@0 | 235 | was supplied in the 'request'. |
paul@0 | 236 | """ |
paul@0 | 237 | |
paul@0 | 238 | argname = getQualifiedParameterName(prefix, argname) |
paul@0 | 239 | return getParameter(request, argname, default) |
paul@0 | 240 | |
paul@0 | 241 | def getQualifiedParameterName(prefix, argname): |
paul@0 | 242 | |
paul@0 | 243 | """ |
paul@0 | 244 | Return the qualified parameter name using the given 'prefix' and 'argname'. |
paul@0 | 245 | """ |
paul@0 | 246 | |
paul@0 | 247 | if prefix is None: |
paul@0 | 248 | return argname |
paul@0 | 249 | else: |
paul@0 | 250 | return "%s-%s" % (prefix, argname) |
paul@0 | 251 | |
paul@0 | 252 | # Page-related functions. |
paul@0 | 253 | |
paul@0 | 254 | def getPrettyPageName(page): |
paul@0 | 255 | |
paul@0 | 256 | "Return a nicely formatted title/name for the given 'page'." |
paul@0 | 257 | |
paul@0 | 258 | title = page.split_title(force=1) |
paul@0 | 259 | return getPrettyTitle(title) |
paul@0 | 260 | |
paul@0 | 261 | def linkToPage(request, page, text, query_string=None): |
paul@0 | 262 | |
paul@0 | 263 | """ |
paul@0 | 264 | Using 'request', return a link to 'page' with the given link 'text' and |
paul@0 | 265 | optional 'query_string'. |
paul@0 | 266 | """ |
paul@0 | 267 | |
paul@0 | 268 | text = wikiutil.escape(text) |
paul@0 | 269 | return page.link_to_raw(request, text, query_string) |
paul@0 | 270 | |
paul@0 | 271 | def linkToResource(url, request, text, query_string=None): |
paul@0 | 272 | |
paul@0 | 273 | """ |
paul@0 | 274 | Using 'request', return a link to 'url' with the given link 'text' and |
paul@0 | 275 | optional 'query_string'. |
paul@0 | 276 | """ |
paul@0 | 277 | |
paul@0 | 278 | if query_string: |
paul@0 | 279 | query_string = wikiutil.makeQueryString(query_string) |
paul@0 | 280 | url = "%s?%s" % (url, query_string) |
paul@0 | 281 | |
paul@0 | 282 | formatter = request.page and getattr(request.page, "formatter", None) or request.html_formatter |
paul@0 | 283 | |
paul@0 | 284 | output = [] |
paul@0 | 285 | output.append(formatter.url(1, url)) |
paul@0 | 286 | output.append(formatter.text(text)) |
paul@0 | 287 | output.append(formatter.url(0)) |
paul@0 | 288 | return "".join(output) |
paul@0 | 289 | |
paul@0 | 290 | def getFullPageName(parent, title): |
paul@0 | 291 | |
paul@0 | 292 | """ |
paul@0 | 293 | Return a full page name from the given 'parent' page (can be empty or None) |
paul@0 | 294 | and 'title' (a simple page name). |
paul@0 | 295 | """ |
paul@0 | 296 | |
paul@0 | 297 | if parent: |
paul@0 | 298 | return "%s/%s" % (parent.rstrip("/"), title) |
paul@0 | 299 | else: |
paul@0 | 300 | return title |
paul@0 | 301 | |
paul@0 | 302 | # vim: tabstop=4 expandtab shiftwidth=4 |