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 prefs = getContentPreferences(accept) 154 return prefs.get_preferred_types(mimetypes) 155 156 def writeHeaders(request, mimetype, metadata, status=None): 157 158 """ 159 Using the 'request', write resource headers using the given 'mimetype', 160 based on the given 'metadata'. If the optional 'status' is specified, set 161 the status header to the given value. 162 """ 163 164 send_headers = get_send_headers(request) 165 166 # Define headers. 167 168 headers = ["Content-Type: %s; charset=%s" % (mimetype, config.charset)] 169 170 # Define the last modified time. 171 # NOTE: Consider using request.httpDate. 172 173 latest_timestamp = metadata.get("last-modified") 174 if latest_timestamp: 175 headers.append("Last-Modified: %s" % latest_timestamp.as_HTTP_datetime_string()) 176 177 if status: 178 headers.append("Status: %s" % status) 179 180 send_headers(headers) 181 182 def getUpdatedTime(metadata): 183 184 """ 185 Return the last updated time based on the given 'metadata', using the 186 current time if no explicit last modified time is specified. 187 """ 188 189 # NOTE: We could attempt to get the last edit time of a fragment. 190 191 latest_timestamp = metadata.get("last-modified") 192 if latest_timestamp: 193 return latest_timestamp.as_ISO8601_datetime_string() 194 else: 195 return getCurrentTime().as_ISO8601_datetime_string() 196 197 # vim: tabstop=4 expandtab shiftwidth=4