1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - MoinShare library 4 5 @copyright: 2011, 2012, 2013 by Paul Boddie <paul@boddie.org.uk> 6 @license: GNU GPL (v2 or later), see COPYING.txt for details. 7 """ 8 9 from ContentTypeSupport import getContentPreferences 10 from DateSupport import getCurrentTime 11 from MoinSupport import * 12 from MoinMoin import wikiutil 13 import re 14 15 try: 16 from cStringIO import StringIO 17 except ImportError: 18 from StringIO import StringIO 19 20 escape = wikiutil.escape 21 _getFragments = getFragments 22 23 __version__ = "0.1" 24 25 # More Moin 1.9 compatibility functions. 26 27 def has_member(request, groupname, username): 28 if hasattr(request.dicts, "has_member"): 29 return request.dicts.has_member(groupname, username) 30 else: 31 return username in request.dicts.get(groupname, []) 32 33 # Fragments employ a "moinshare" attribute. 34 35 fragment_attribute = "moinshare" 36 37 def getFragments(s): 38 39 "Return all fragments in 's' having the MoinShare fragment attribute." 40 41 fragments = [] 42 for format, attributes, body in _getFragments(s): 43 if attributes.has_key(fragment_attribute): 44 fragments.append((format, attributes, body)) 45 return fragments 46 47 def getOutputTypes(request, format): 48 49 """ 50 Using the 'request' and the 'format' of a fragment, return the media types 51 available for the fragment. 52 """ 53 54 # This uses an extended parser API method if available. 55 56 parser = getParserClass(request, format) 57 if hasattr(parser, "getOutputTypes"): 58 return parser.getOutputTypes() 59 else: 60 return ["text/html"] 61 62 def getPreferredOutputTypes(request, mimetypes): 63 64 """ 65 Using the 'request', perform content negotiation, obtaining mimetypes common 66 to the fragment (given by 'mimetypes') and the client (found in the Accept 67 header). 68 """ 69 70 accept = getHeader(request, "Accept", "HTTP") 71 if accept: 72 prefs = getContentPreferences(accept) 73 return prefs.get_preferred_types(mimetypes) 74 else: 75 return mimetypes 76 77 def getUpdatedTime(metadata): 78 79 """ 80 Return the last updated time based on the given 'metadata', using the 81 current time if no explicit last modified time is specified. 82 """ 83 84 # NOTE: We could attempt to get the last edit time of a fragment. 85 86 latest_timestamp = metadata.get("last-modified") 87 if latest_timestamp: 88 return latest_timestamp.as_ISO8601_datetime_string() 89 else: 90 return getCurrentTime().as_ISO8601_datetime_string() 91 92 def getUpdateSources(request, sources_page): 93 94 """ 95 Using the 'request', return the update sources defined on the given 96 'sources_page'. 97 """ 98 99 # Remote sources are accessed via dictionary page definitions. 100 101 return getWikiDict(sources_page, request) 102 103 # Entry/update classes. 104 105 class Update: 106 107 "A feed update entry." 108 109 def __init__(self): 110 self.title = None 111 self.link = None 112 self.content = None 113 self.content_type = None 114 self.updated = None 115 116 # Page-related attributes. 117 118 self.fragment = None 119 self.preferred = None 120 121 def __cmp__(self, other): 122 if self.updated is None and other.updated is not None: 123 return 1 124 elif self.updated is not None and other.updated is None: 125 return -1 126 else: 127 return cmp(self.updated, other.updated) 128 129 # Update retrieval from pages. 130 131 def getUpdatesFromPage(page, request): 132 133 """ 134 Get updates from the given 'page' using the 'request'. A list of update 135 objects is returned. 136 """ 137 138 updates = [] 139 140 # NOTE: Use the updated datetime from the page for updates. 141 # NOTE: The published and updated details would need to be deduced from 142 # NOTE: the page history instead of being taken from the page as a whole. 143 144 metadata = getMetadata(page) 145 updated = getUpdatedTime(metadata) 146 147 # Get the fragment regions for the page. 148 149 for n, (format, attributes, body) in enumerate(getFragments(page.get_raw_body())): 150 151 # Produce a fragment identifier. 152 # NOTE: Choose a more robust identifier where none is explicitly given. 153 154 update = Update() 155 156 update.fragment = attributes.get("fragment", str(n)) 157 update.title = attributes.get("summary", "Update #%d" % n) 158 159 # Get the preferred content types available for the fragment. 160 161 update.preferred = getPreferredOutputTypes(request, getOutputTypes(request, format)) 162 163 # Try and obtain some suitable content for the entry. 164 # NOTE: Could potentially get a summary for the fragment. 165 166 update.content = None 167 168 if "text/html" in update.preferred: 169 parser_cls = getParserClass(request, format) 170 parser = parser_cls(body, request) 171 172 if format == "html": 173 update.content = body 174 elif hasattr(parser, "formatForOutputType"): 175 s = StringIO() 176 parser.formatForOutputType("text/html", write=s.write) 177 update.content = s.getvalue() 178 else: 179 fmt = request.html_formatter 180 fmt.setPage(page) 181 update.content = formatText(body, request, fmt, parser_cls) 182 183 update.content_type = "text/html" 184 185 update.link = page.url(request) 186 update.updated = updated 187 188 updates.append(update) 189 190 return updates 191 192 # Source management. 193 194 def getUpdateSources(pagename, request): 195 196 "Return the update sources from the given 'pagename' using the 'request'." 197 198 sources = {} 199 200 source_definitions = getWikiDict(pagename, request) 201 202 if source_definitions: 203 for name, value in source_definitions.items(): 204 sources[name] = getSourceParameters(value) 205 206 return sources 207 208 def getSourceParameters(source_definition): 209 210 "Return the parameters from the given 'source_definition' string." 211 212 parameters = {} 213 unqualified = ("type", "location") 214 215 for arg in source_definition.split(): 216 try: 217 argname, argvalue = arg.split("=", 1) 218 219 # Detect unlikely parameter names. 220 221 if not argname.isalpha(): 222 raise ValueError 223 224 parameters[argname] = argvalue 225 226 # Unqualified parameters are assumed to be one of a recognised set. 227 228 except ValueError: 229 for argname in unqualified: 230 if not parameters.has_key(argname): 231 parameters[argname] = arg 232 break 233 234 return parameters 235 236 # vim: tabstop=4 expandtab shiftwidth=4