1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - MoinShare library 4 5 @copyright: 2011, 2012 by Paul Boddie <paul@boddie.org.uk> 6 @license: GNU GPL (v2 or later), see COPYING.txt for details. 7 """ 8 9 from MoinSupport import * 10 from MoinMoin import config, wikiutil 11 from DateSupport import getCurrentTime 12 import re 13 14 escape = wikiutil.escape 15 16 __version__ = "0.1" 17 18 # More Moin 1.9 compatibility functions. 19 20 def has_member(request, groupname, username): 21 if hasattr(request.dicts, "has_member"): 22 return request.dicts.has_member(groupname, username) 23 else: 24 return username in request.dicts.get(groupname, []) 25 26 # Extraction of shared fragments. 27 28 marker_regexp_str = r"([{]{3,}|[}]{3,})" 29 marker_regexp = re.compile(marker_regexp_str, re.MULTILINE | re.DOTALL) # {{{... or }}}... 30 31 # Fragments employ a "moinshare" attribute. 32 33 fragment_prelude = "#!" 34 fragment_attribute = "moinshare" 35 36 def getRegions(s): 37 38 "Parse the string 's', returning a list of shared regions." 39 40 regions = [] 41 marker = None 42 is_region = True 43 44 for match_text in marker_regexp.split(s): 45 46 # Capture section text. 47 48 if is_region and marker: 49 regions[-1] += match_text 50 51 # Handle section markers. 52 53 elif not is_region: 54 55 # Close any open sections, returning to exposed text regions. 56 57 if marker: 58 if match_text.startswith("}") and len(marker) == len(match_text): 59 marker = None 60 61 # Without a current marker, start a section if an appropriate marker 62 # is given. 63 64 elif match_text.startswith("{"): 65 marker = match_text 66 regions.append("") 67 68 # Markers and section text are added to the current region. 69 70 regions[-1] += match_text 71 72 # Exposed text is ignored. 73 74 # The match text alternates between text between markers and the markers 75 # themselves. 76 77 is_region = not is_region 78 79 return regions 80 81 def getFragmentsFromRegions(regions): 82 83 """ 84 Return fragments from the given 'regions', each having the form 85 (format, arguments, body text). 86 """ 87 88 fragments = [] 89 90 for region in regions: 91 body = region.lstrip("{").rstrip("}").lstrip() 92 if body.startswith(fragment_prelude): 93 arguments, body = body[len(fragment_prelude):].split("\n", 1) 94 95 # Get any parser/format declaration. 96 97 if arguments and not arguments[0].isspace(): 98 format, arguments = arguments.split(None, 1) 99 else: 100 format = None 101 102 # Get the attributes/arguments for the region. 103 104 attributes = parseAttributes(arguments, False) 105 106 # If the format is the MoinShare attribute, move it into the 107 # dictionary. 108 109 if format.lower() == fragment_attribute: 110 attributes[fragment_attribute] = True 111 format = None 112 113 # Only collect appropriate regions. 114 115 if attributes.has_key(fragment_attribute): 116 fragments.append((format, attributes, body)) 117 118 return fragments 119 120 def getFragments(s): 121 122 """ 123 Return fragments for the given string 's', each having the form 124 (arguments, body text). 125 """ 126 127 return getFragmentsFromRegions(getRegions(s)) 128 129 def getOutputTypes(request, format): 130 131 """ 132 Using the 'request' and the 'format' of a fragment, return the media types 133 available for the fragment. 134 """ 135 136 # This uses an extended parser API method if available. 137 138 parser = getParserClass(request, format) 139 if hasattr(parser, "getOutputTypes"): 140 return parser.getOutputTypes() 141 else: 142 return ["text/html"] 143 144 def getPreferredOutputTypes(request, mimetypes): 145 146 """ 147 Using the 'request', perform content negotiation, obtaining mimetypes common 148 to the fragment (given by 'mimetypes') and the client (found in the Accept 149 header). 150 """ 151 152 accept = getHeader(request, "Accept", "HTTP") 153 if accept: 154 prefs = getContentPreferences(accept) 155 return prefs.get_preferred_types(mimetypes) 156 else: 157 return mimetypes 158 159 def writeHeaders(request, mimetype, metadata, status=None): 160 161 """ 162 Using the 'request', write resource headers using the given 'mimetype', 163 based on the given 'metadata'. If the optional 'status' is specified, set 164 the status header to the given value. 165 """ 166 167 send_headers = get_send_headers(request) 168 169 # Define headers. 170 171 headers = ["Content-Type: %s; charset=%s" % (mimetype, config.charset)] 172 173 # Define the last modified time. 174 # NOTE: Consider using request.httpDate. 175 176 latest_timestamp = metadata.get("last-modified") 177 if latest_timestamp: 178 headers.append("Last-Modified: %s" % latest_timestamp.as_HTTP_datetime_string()) 179 180 if status: 181 headers.append("Status: %s" % status) 182 183 send_headers(headers) 184 185 def getUpdatedTime(metadata): 186 187 """ 188 Return the last updated time based on the given 'metadata', using the 189 current time if no explicit last modified time is specified. 190 """ 191 192 # NOTE: We could attempt to get the last edit time of a fragment. 193 194 latest_timestamp = metadata.get("last-modified") 195 if latest_timestamp: 196 return latest_timestamp.as_ISO8601_datetime_string() 197 else: 198 return getCurrentTime().as_ISO8601_datetime_string() 199 200 # vim: tabstop=4 expandtab shiftwidth=4