paul@0 | 1 | # -*- coding: iso-8859-1 -*- |
paul@0 | 2 | """ |
paul@0 | 3 | MoinMoin - AddLinkToPage |
paul@0 | 4 | |
paul@0 | 5 | Add a link using a form in the page, getting details of the linked document |
paul@0 | 6 | and inserting them with the link itself. |
paul@0 | 7 | |
paul@0 | 8 | @copyright: 2010 Paul Boddie <paul@boddie.org.uk> |
paul@0 | 9 | @license: GNU GPL, see COPYING for details. |
paul@0 | 10 | """ |
paul@0 | 11 | |
paul@0 | 12 | Dependencies = ['pages'] |
paul@0 | 13 | |
paul@1 | 14 | from MoinMoin import wikiutil |
paul@0 | 15 | from MoinMoin.action import ActionBase |
paul@0 | 16 | from MoinMoin.PageEditor import PageEditor |
paul@0 | 17 | from MoinContentSupport import ActionSupport |
paul@1 | 18 | import urllib |
paul@0 | 19 | import re |
paul@0 | 20 | |
paul@1 | 21 | # Page parsing. |
paul@1 | 22 | |
paul@0 | 23 | macro_pattern = re.compile(ur'^(?P<leading>.*?)<<AddLinkToPage\((?P<identifier>[^\s,)]+).*?\)>>(?P<trailing>.*)$', |
paul@0 | 24 | re.MULTILINE | re.UNICODE) |
paul@0 | 25 | |
paul@1 | 26 | # Link visiting and parsing. |
paul@1 | 27 | |
paul@1 | 28 | title_pattern = re.compile(ur'<(?P<tag>title|h\d)(\s.*?)?>(?P<title>.*?)</(?P=tag)>', re.MULTILINE | re.UNICODE | re.DOTALL) |
paul@1 | 29 | paragraph_pattern = re.compile(ur'<p(\s.*?)?>(?P<text>.*?)(?=<p(\s.*?)?>|</p>)', re.MULTILINE | re.UNICODE | re.DOTALL) |
paul@1 | 30 | tag_pattern = re.compile(ur'<.*?>', re.MULTILINE | re.UNICODE | re.DOTALL) |
paul@1 | 31 | |
paul@1 | 32 | def get_link_info(link): |
paul@1 | 33 | |
paul@1 | 34 | "Get information from the given 'link'." |
paul@1 | 35 | |
paul@1 | 36 | # NOTE: Insist on remote URLs! |
paul@1 | 37 | |
paul@1 | 38 | try: |
paul@1 | 39 | f = urllib.urlopen(link) |
paul@1 | 40 | except IOError: |
paul@1 | 41 | return None |
paul@1 | 42 | |
paul@1 | 43 | try: |
paul@1 | 44 | s = f.read() |
paul@1 | 45 | first_title = "" |
paul@1 | 46 | |
paul@1 | 47 | for title_match in title_pattern.finditer(s): |
paul@1 | 48 | title = title_match.group("title").strip() |
paul@1 | 49 | start, end = title_match.span() |
paul@1 | 50 | |
paul@1 | 51 | if not first_title: |
paul@1 | 52 | first_title = title |
paul@1 | 53 | |
paul@1 | 54 | for intro_match in paragraph_pattern.finditer(s[end:]): |
paul@1 | 55 | intro = get_flattened_content(intro_match.group("text")).strip() |
paul@1 | 56 | if intro: |
paul@1 | 57 | return title, intro |
paul@1 | 58 | finally: |
paul@1 | 59 | f.close() |
paul@1 | 60 | |
paul@1 | 61 | return first_title, "" |
paul@1 | 62 | |
paul@1 | 63 | def get_flattened_content(s): |
paul@1 | 64 | |
paul@1 | 65 | "Get HTML or XHTML without the tags." |
paul@1 | 66 | |
paul@1 | 67 | l = [] |
paul@1 | 68 | last = 0 |
paul@1 | 69 | for match in tag_pattern.finditer(s): |
paul@1 | 70 | start, end = match.span() |
paul@1 | 71 | l.append(s[last:start]) |
paul@1 | 72 | last = end |
paul@1 | 73 | l.append(s[last:]) |
paul@1 | 74 | return "".join(l).replace("\n", " ") |
paul@1 | 75 | |
paul@0 | 76 | # Action class and supporting functions. |
paul@0 | 77 | |
paul@0 | 78 | class AddLinkToPage(ActionBase, ActionSupport): |
paul@0 | 79 | |
paul@0 | 80 | "An action adding links to pages." |
paul@0 | 81 | |
paul@1 | 82 | def get_form_html(self, buttons_html): |
paul@1 | 83 | _ = self._ |
paul@1 | 84 | request = self.request |
paul@1 | 85 | page = self.page |
paul@1 | 86 | form = self.get_form() |
paul@1 | 87 | |
paul@1 | 88 | identifier = form.get("identifier", [None])[0] |
paul@1 | 89 | link = form.get("link", [None])[0] |
paul@1 | 90 | insert_before = form.get('insert_before', [""])[0] |
paul@1 | 91 | title = "" |
paul@1 | 92 | introduction = "" |
paul@1 | 93 | |
paul@1 | 94 | # Acquire information from the link. |
paul@1 | 95 | |
paul@1 | 96 | if link is not None: |
paul@1 | 97 | link_info = get_link_info(link) |
paul@1 | 98 | |
paul@1 | 99 | # NOTE: Perhaps show a message upon success/failure. |
paul@1 | 100 | |
paul@1 | 101 | if link_info is not None: |
paul@1 | 102 | title, introduction = link_info |
paul@1 | 103 | |
paul@1 | 104 | d = { |
paul@1 | 105 | "identifier" : wikiutil.escape(identifier, 1), |
paul@1 | 106 | "insert_before" : insert_before and "true" or "", |
paul@1 | 107 | "link" : wikiutil.escape(link, 1), |
paul@1 | 108 | "title" : wikiutil.escape(title, 1), |
paul@1 | 109 | "intro" : wikiutil.escape(introduction, 1), |
paul@1 | 110 | "url_label" : wikiutil.escape(_("URL")), |
paul@1 | 111 | "title_label" : wikiutil.escape(_("Title")), |
paul@1 | 112 | "intro_label" : wikiutil.escape(_("Introduction")), |
paul@1 | 113 | "description_label" : wikiutil.escape(_("Description")), |
paul@1 | 114 | "submit_label" : wikiutil.escape(_("Submit link")), |
paul@1 | 115 | "script_name" : request.getScriptname(), |
paul@1 | 116 | "page_url" : wikiutil.quoteWikinameURL(page.page_name) |
paul@1 | 117 | } |
paul@1 | 118 | |
paul@1 | 119 | html = ''' |
paul@1 | 120 | <form class="macro" method="POST" action="%(script_name)s/%(page_url)s"> |
paul@1 | 121 | <input type="hidden" name="identifier" value="%(identifier)s" /> |
paul@1 | 122 | <input type="hidden" name="doit" value="1" /> |
paul@1 | 123 | <input type="hidden" name="insert_before" value="%(insert_before)s" /> |
paul@1 | 124 | <input type="hidden" name="action" value="AddLinkToPage" /> |
paul@1 | 125 | <table> |
paul@1 | 126 | <tr> |
paul@1 | 127 | <td class="label">%(url_label)s</td> |
paul@1 | 128 | <td><input type="text" name="link" value="%(link)s" size="40" /></td> |
paul@1 | 129 | </tr> |
paul@1 | 130 | <tr> |
paul@1 | 131 | <td class="label">%(title_label)s</td> |
paul@1 | 132 | <td><input type="text" name="title" value="%(title)s" size="40" /></td> |
paul@1 | 133 | </tr> |
paul@1 | 134 | <tr> |
paul@1 | 135 | <td class="label">%(intro_label)s</td> |
paul@1 | 136 | <td><textarea name="introduction" cols="40" rows="3">%(intro)s</textarea></td> |
paul@1 | 137 | </tr> |
paul@1 | 138 | <tr> |
paul@1 | 139 | <td class="label">%(description_label)s</td> |
paul@1 | 140 | <td><input type="text" name="description" size="40" /></td> |
paul@1 | 141 | </tr> |
paul@1 | 142 | <tr> |
paul@1 | 143 | <td colspan="2"><input type="submit" value="%(submit_label)s" /></td> |
paul@1 | 144 | </tr> |
paul@1 | 145 | </table> |
paul@1 | 146 | </form>''' % d |
paul@1 | 147 | |
paul@1 | 148 | return html |
paul@1 | 149 | |
paul@0 | 150 | def do_action(self): |
paul@0 | 151 | |
paul@0 | 152 | "Create the new event." |
paul@0 | 153 | |
paul@0 | 154 | _ = self._ |
paul@0 | 155 | form = self.get_form() |
paul@0 | 156 | |
paul@0 | 157 | # If no title exists in the request, an error message is returned. |
paul@0 | 158 | |
paul@0 | 159 | identifier = form.get("identifier", [None])[0] |
paul@1 | 160 | link = form.get("link", [None])[0] |
paul@0 | 161 | |
paul@0 | 162 | if not identifier: |
paul@0 | 163 | return 0, _("No identifier specified.") |
paul@0 | 164 | |
paul@0 | 165 | if not link: |
paul@0 | 166 | return 0, _("No link specified.") |
paul@0 | 167 | |
paul@0 | 168 | return self.add_link_to_page(identifier, link) |
paul@0 | 169 | |
paul@0 | 170 | def render_success(self, msg, msgtype=None): |
paul@0 | 171 | |
paul@0 | 172 | """ |
paul@0 | 173 | Render neither 'msg' nor 'msgtype' since redirection should occur |
paul@0 | 174 | instead. |
paul@0 | 175 | NOTE: msgtype is optional because MoinMoin 1.5.x does not support it. |
paul@0 | 176 | """ |
paul@0 | 177 | |
paul@0 | 178 | pass |
paul@0 | 179 | |
paul@0 | 180 | def add_link_to_page(self, identifier, link): |
paul@0 | 181 | |
paul@0 | 182 | """ |
paul@0 | 183 | For the macro with the given 'identifier', add 'link' to the current |
paul@0 | 184 | page. |
paul@0 | 185 | """ |
paul@0 | 186 | |
paul@0 | 187 | _ = self._ |
paul@0 | 188 | request = self.request |
paul@0 | 189 | page = self.page |
paul@0 | 190 | formatter = request.formatter |
paul@0 | 191 | form = self.get_form() |
paul@0 | 192 | |
paul@0 | 193 | # Get the link details. |
paul@0 | 194 | |
paul@0 | 195 | title = form.get('title', [link])[0] |
paul@0 | 196 | introduction = form.get('introduction', [""])[0] |
paul@0 | 197 | description = form.get('description', [""])[0] |
paul@0 | 198 | insert_before = form.get('insert_before', [""])[0] |
paul@0 | 199 | |
paul@0 | 200 | # Encode the link details. |
paul@0 | 201 | # NOTE: Should support different formatting options. |
paul@0 | 202 | |
paul@0 | 203 | link_details = "%s[[%s%s]]%s" % ( |
paul@1 | 204 | introduction and (get_verbatim('"%s" ' % introduction)) or "", |
paul@0 | 205 | link, |
paul@0 | 206 | title and ('|%s' % title) or "", |
paul@0 | 207 | description and (" - ''%s''" % description) or "" |
paul@0 | 208 | ) |
paul@0 | 209 | |
paul@0 | 210 | # Open the page for editing. |
paul@0 | 211 | |
paul@0 | 212 | new_page = PageEditor(request, page.page_name) |
paul@0 | 213 | |
paul@0 | 214 | # Parse the page. |
paul@0 | 215 | |
paul@0 | 216 | page_body = page.get_raw_body() |
paul@0 | 217 | |
paul@0 | 218 | for match in macro_pattern.finditer(page_body): |
paul@0 | 219 | macro_identifier = match.group("identifier") |
paul@0 | 220 | leading_text = match.group("leading") |
paul@0 | 221 | trailing_text = match.group("trailing") |
paul@0 | 222 | start, end = match.span() |
paul@0 | 223 | |
paul@0 | 224 | # Where this identifier matches this macro's identifier, insert the |
paul@0 | 225 | # link details. |
paul@0 | 226 | |
paul@0 | 227 | if macro_identifier == identifier: |
paul@0 | 228 | if insert_before: |
paul@0 | 229 | page_body = page_body[:start] + leading_text + link_details + trailing_text + "\n" + page_body[start:] |
paul@0 | 230 | else: |
paul@0 | 231 | page_body = page_body[:end] + "\n" + leading_text + link_details + trailing_text + page_body[end:] |
paul@0 | 232 | |
paul@0 | 233 | # Save the new version of the page. |
paul@0 | 234 | |
paul@0 | 235 | new_page.saveText(page_body, 0) |
paul@0 | 236 | break |
paul@0 | 237 | |
paul@0 | 238 | # NOTE: Perhaps show a message upon failure. |
paul@0 | 239 | |
paul@0 | 240 | request.http_redirect(page.url(request)) |
paul@0 | 241 | return 1, None |
paul@0 | 242 | |
paul@1 | 243 | def get_verbatim(s): |
paul@1 | 244 | |
paul@1 | 245 | "Return 's' encoded as verbatim text." |
paul@1 | 246 | |
paul@1 | 247 | output = [] |
paul@1 | 248 | |
paul@1 | 249 | for part in s.split('"'): |
paul@1 | 250 | if part: |
paul@1 | 251 | output.append('<<Verbatim("%s")>>' % part) |
paul@1 | 252 | else: |
paul@1 | 253 | output.append('') |
paul@1 | 254 | |
paul@1 | 255 | return '"'.join(output) |
paul@1 | 256 | |
paul@0 | 257 | # Action function. |
paul@0 | 258 | |
paul@0 | 259 | def execute(pagename, request): |
paul@0 | 260 | AddLinkToPage(pagename, request).render() |
paul@0 | 261 | |
paul@0 | 262 | # vim: tabstop=4 expandtab shiftwidth=4 |