1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - SharedUpdates Action 4 5 @copyright: 2012 by Paul Boddie <paul@boddie.org.uk> 6 @license: GNU GPL (v2 or later), see COPYING.txt for details. 7 """ 8 9 from MoinMoin.action import ActionBase 10 from MoinMoin import config 11 from MoinMoin import wikiutil 12 from MoinShare import * 13 from DateSupport import getCurrentTime 14 15 Dependencies = ['pages'] 16 17 # Action class and supporting functions. 18 19 class SharedUpdates(ActionBase, ActionSupport): 20 21 "A summary dialogue requesting various parameters." 22 23 def get_form_html(self, buttons_html): 24 _ = self._ 25 request = self.request 26 form = self.get_form() 27 page = self.page 28 29 pagename = form.get("pagename", [page.page_name])[0] 30 31 d = { 32 "buttons_html" : buttons_html, 33 "pagename_label" : escape(_("Page name for updates")), 34 "pagename" : escattr(pagename), 35 } 36 37 return ''' 38 <table> 39 <tr> 40 <td class="label"><label>%(pagename_label)s</label></td> 41 <td class="content"> 42 <input name="pagename" type="text" size="40" value="%(pagename)s" /> 43 </td> 44 </tr> 45 <tr> 46 <td></td> 47 <td class="buttons"> 48 %(buttons_html)s 49 </td> 50 </tr> 51 </table> 52 ''' % d 53 54 def do_action(self): 55 56 "Write the syndication resource." 57 58 write_resource(self.request) 59 return 1, None 60 61 def render_success(self, msg, msgtype=None): 62 63 """ 64 Render neither 'msg' nor 'msgtype' since a resource has already been 65 produced. 66 NOTE: msgtype is optional because MoinMoin 1.5.x does not support it. 67 """ 68 69 pass 70 71 def write_resource(request): 72 73 """ 74 For the given 'request', write an Atom summary of updates found on the 75 specified page. 76 See: http://tools.ietf.org/html/rfc4287 77 """ 78 79 form = get_form(request) 80 81 pagename = form.get("pagename", [request.page.page_name])[0] 82 83 # Output summary data... 84 85 send_headers = get_send_headers(request) 86 87 # Define headers. 88 89 headers = ["Content-Type: application/atom+xml; charset=%s" % config.charset] 90 91 # Define the last modified time. 92 # NOTE: We could attempt to get the last edit time of the fragment. 93 94 page = Page(request, pagename) 95 metadata = getMetadata(page) 96 97 # NOTE: Consider using request.httpDate. 98 99 if metadata.has_key("last-modified"): 100 latest_timestamp = metadata["last-modified"] 101 headers.append("Last-Modified: %s" % latest_timestamp.as_HTTP_datetime_string()) 102 updated = latest_timestamp.as_ISO8601_datetime_string() 103 else: 104 updated = getCurrentTime().as_ISO8601_datetime_string() 105 106 send_headers(headers) 107 108 # Atom output... 109 110 # Using the page name and the page URL in the title, link and 111 # subtitle. 112 113 path_info = getPathInfo(request) 114 link = "%s%s" % (request.getBaseURL(), path_info) 115 116 d = { 117 "title" : escape(path_info[1:]), 118 "link" : escape(link), 119 "href" : escattr(link), 120 "updated" : escape(updated), 121 } 122 123 request.write('''\ 124 <?xml version="1.0" encoding="utf-8"?>\r 125 <feed xmlns="http://www.w3.org/2005/Atom">\r 126 <title type="text">%(title)s</title>\r 127 <subtitle type="text">Shared updates published on %(link)s</subtitle>\r 128 <link rel="self" href="%(href)s"/>\r 129 <updated>%(updated)s</updated>\r 130 ''' % d) 131 132 # Get the fragment regions for the page. 133 134 for n, (format, attributes, body) in enumerate(getFragments(page.get_raw_body())): 135 136 # Produce a fragment identifier. 137 # NOTE: Choose a more robust identifier where none is explicitly given. 138 139 fragment = attributes.get("fragment", str(n)) 140 summary = attributes.get("summary", "Update #%d" % n) 141 142 # Get the URL that yields only the fragment. 143 144 fragment_link = "%s?action=ShowUpdate&fragment=%s" % (link, fragment) 145 146 # Get the types available for the fragment. 147 # This uses an extended parser API method if available. 148 149 parser = getParserClass(request, format) 150 if hasattr(parser, "getOutputTypes"): 151 mimetypes = parser.getOutputTypes() 152 else: 153 mimetypes = ["text/html"] 154 155 # Perform content negotiation, obtaining mimetypes common to the 156 # fragment and the client. 157 158 accept = getHeader(request, "Accept", "HTTP") 159 prefs = getContentPreferences(accept) 160 preferred = prefs.get_preferred_types(mimetypes) 161 162 download_links = [] 163 164 for mimetype in preferred: 165 specific_link = "%s&mimetype=%s" % (fragment_link, mimetype) 166 167 download_links.append('<link rel="alternate" type="%s" href="%s"/>' % ( 168 escattr(mimetype), escattr(specific_link))) 169 170 # NOTE: Could potentially get a summary for the fragment. 171 # NOTE: The published and updated details would need to be deduced from 172 # NOTE: the page history. 173 174 d = { 175 "title" : escape(summary), 176 "fragment_link" : escape(fragment_link), 177 "download_links" : "\r\n".join(download_links), 178 } 179 180 request.write('''\ 181 <entry>\r 182 <title>%(title)s</title>\r 183 <id>%(fragment_link)s</id>\r 184 %(download_links)s\r 185 </entry>\r 186 ''' % d) 187 188 request.write('</feed>\r\n') 189 190 # Action function. 191 192 def execute(pagename, request): 193 SharedUpdates(pagename, request).render() 194 195 # vim: tabstop=4 expandtab shiftwidth=4