1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - SharedUpdates Action 4 5 @copyright: 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 MoinMoin.action import ActionBase 10 from MoinMoin.Page import Page 11 from MoinMoin import wikiutil 12 from MoinShare import getPreferredOutputTypes, getOutputTypes, getUpdatedTime 13 from MoinSupport import escattr, formatText, get_form, getFragments, \ 14 getMetadata, getParserClass, getPathInfo, writeHeaders, ActionSupport 15 16 try: 17 from cStringIO import StringIO 18 except ImportError: 19 from StringIO import StringIO 20 21 escape = wikiutil.escape 22 23 Dependencies = ['pages'] 24 25 # Action class and supporting functions. 26 27 class SharedUpdates(ActionBase, ActionSupport): 28 29 "An update manifest retrieval dialogue requesting various parameters." 30 31 def get_form_html(self, buttons_html): 32 _ = self._ 33 request = self.request 34 form = self.get_form() 35 page = self.page 36 37 pagename = form.get("pagename", [page.page_name])[0] 38 39 d = { 40 "buttons_html" : buttons_html, 41 "pagename_label" : escape(_("Page name for updates")), 42 "pagename" : escattr(pagename), 43 } 44 45 return ''' 46 <table> 47 <tr> 48 <td class="label"><label>%(pagename_label)s</label></td> 49 <td class="content"> 50 <input name="pagename" type="text" size="40" value="%(pagename)s" /> 51 </td> 52 </tr> 53 <tr> 54 <td></td> 55 <td class="buttons"> 56 %(buttons_html)s 57 </td> 58 </tr> 59 </table> 60 ''' % d 61 62 def do_action(self): 63 64 "Write the syndication resource." 65 66 write_resource(self.request) 67 return 1, None 68 69 def render_success(self, msg, msgtype=None): 70 71 """ 72 Render neither 'msg' nor 'msgtype' since a resource has already been 73 produced. 74 NOTE: msgtype is optional because MoinMoin 1.5.x does not support it. 75 """ 76 77 pass 78 79 def write_resource(request): 80 81 """ 82 For the given 'request', write an Atom summary of updates found on the 83 specified page. 84 See: http://tools.ietf.org/html/rfc4287 85 """ 86 87 form = get_form(request) 88 89 pagename = form.get("pagename", [request.page.page_name])[0] 90 91 page = Page(request, pagename) 92 metadata = getMetadata(page) 93 94 # Output summary data... 95 96 writeHeaders(request, "application/atom+xml", metadata) 97 updated = getUpdatedTime(metadata) 98 99 # Atom output... 100 101 # Using the page name and the page URL in the title, link and 102 # subtitle. 103 104 path_info = getPathInfo(request) 105 link = "%s%s" % (request.getBaseURL(), path_info) 106 107 d = { 108 "title" : escape(path_info[1:]), 109 "link" : escape(link), 110 "href" : escattr(link), 111 "updated" : escape(updated), 112 } 113 114 # Start the output. 115 116 request.write('''\ 117 <?xml version="1.0" encoding="utf-8"?>\r 118 <feed xmlns="http://www.w3.org/2005/Atom">\r 119 <title type="text">%(title)s</title>\r 120 <subtitle type="text">Shared updates published on %(link)s</subtitle>\r 121 <link rel="self" href="%(href)s"/>\r 122 <updated>%(updated)s</updated>\r 123 ''' % d) 124 125 # Get the fragment regions for the page. 126 127 for n, (format, attributes, body) in enumerate(getFragments(page.get_raw_body())): 128 129 # Produce a fragment identifier. 130 # NOTE: Choose a more robust identifier where none is explicitly given. 131 132 fragment = attributes.get("fragment", str(n)) 133 summary = attributes.get("summary", "Update #%d" % n) 134 135 # Get the URL that yields only the fragment. 136 137 fragment_link = "%s?action=SharedUpdate&fragment=%s" % (link, fragment) 138 139 # Get the preferred content types available for the fragment. 140 141 preferred = getPreferredOutputTypes(request, getOutputTypes(request, format)) 142 143 download_links = [] 144 145 for mimetype in preferred: 146 specific_link = "%s&type=%s&doit=1" % (fragment_link, mimetype) 147 148 download_links.append('<link rel="alternate" type="%s" href="%s"/>' % ( 149 escattr(mimetype), escattr(specific_link))) 150 151 # Try and obtain some suitable content for the entry. 152 # NOTE: Could potentially get a summary for the fragment. 153 154 content = None 155 156 if "text/html" in preferred: 157 parser_cls = getParserClass(request, format) 158 parser = parser_cls(body, request) 159 160 if format == "html": 161 content = body 162 elif hasattr(parser, "formatForOutputType"): 163 s = StringIO() 164 parser.formatForOutputType("text/html", write=s.write) 165 content = s.getvalue() 166 else: 167 fmt = request.html_formatter 168 fmt.setPage(page) 169 content = formatText(body, request, fmt, parser_cls) 170 171 # NOTE: The published and updated details would need to be deduced from 172 # NOTE: the page history instead of being taken for the page as a whole. 173 174 d = { 175 "title" : escape(summary), 176 "fragment_link" : escape(fragment_link), 177 "download_links" : "\r\n".join(download_links), 178 "content" : content and ('<content type="html">%s</content>' % escape(content)) or "", 179 "updated" : escape(updated), 180 } 181 182 # Write the entry output. 183 184 request.write('''\ 185 <entry>\r 186 <title>%(title)s</title>\r 187 <id>%(fragment_link)s</id>\r 188 <updated>%(updated)s</updated>\r 189 %(download_links)s\r 190 %(content)s\r 191 </entry>\r 192 ''' % d) 193 194 # End the feed output. 195 196 request.write('</feed>\r\n') 197 198 # Action function. 199 200 def execute(pagename, request): 201 SharedUpdates(pagename, request).render() 202 203 # vim: tabstop=4 expandtab shiftwidth=4