changeset 3149:6749e003d7e2

remove attachments direct serving (cfg.attachments), refactor AttachFile to use formatter for link generation
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Thu, 28 Feb 2008 21:31:18 +0100
parents e1fe8dd52b83
children 8ae94675b9f9
files MoinMoin/action/AttachFile.py MoinMoin/config/multiconfig.py MoinMoin/formatter/text_html.py MoinMoin/macro/EmbedObject.py
diffstat 4 files changed, 118 insertions(+), 168 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/action/AttachFile.py	Thu Feb 28 17:56:44 2008 +0100
+++ b/MoinMoin/action/AttachFile.py	Thu Feb 28 21:31:18 2008 +0100
@@ -23,7 +23,7 @@
                 2005 MoinMoin:AlexanderSchremmer,
                 2005 DiegoOngaro at ETSZONE (diego@etszone.com),
                 2005-2007 MoinMoin:ReimarBauer,
-                2007 MoinMoin:ThomasWaldmann
+                2007-2008 MoinMoin:ThomasWaldmann
     @license: GNU GPL, see COPYING for details.
 """
 
@@ -38,10 +38,6 @@
 
 action_name = __name__.split('.')[-1]
 
-def htdocs_access(request):
-    return isinstance(request.cfg.attachments, type({}))
-
-
 #############################################################################
 ### External interface - these are called from the core code
 #############################################################################
@@ -52,30 +48,17 @@
 def getBasePath(request):
     """ Get base path where page dirs for attachments are stored.
     """
-    if htdocs_access(request):
-        return request.cfg.attachments['dir']
-    else:
-        return request.rootpage.getPagePath('pages')
+    return request.rootpage.getPagePath('pages')
 
 
 def getAttachDir(request, pagename, create=0):
     """ Get directory where attachments for page `pagename` are stored.
     """
-    if htdocs_access(request):
-        # direct file access via webserver, from public htdocs area
-        pagename = wikiutil.quoteWikinameFS(pagename)
-        attach_dir = os.path.join(request.cfg.attachments['dir'], pagename, "attachments")
-        if create and not os.path.isdir(attach_dir):
-            os.makedirs(attach_dir)
+    if request.page and pagename == request.page.page_name:
+        page = request.page # reusing existing page obj is faster
     else:
-        # send file via CGI, from page storage area
-        if request.page and pagename == request.page.page_name:
-            page = request.page # reusing existing page obj is faster
-        else:
-            page = Page(request, pagename)
-        attach_dir = page.getPagePath("attachments", check_create=create)
-
-    return attach_dir
+        page = Page(request, pagename)
+    return page.getPagePath("attachments", check_create=create)
 
 def absoluteName(url, pagename):
     """ Get (pagename, filename) of an attachment: link
@@ -91,51 +74,34 @@
     else:
         return u"/".join(pieces[:-1]), pieces[-1]
 
-def getAttachUrl(pagename, filename, request, addts=0, escaped=0, do='get'):
-    """ Get URL that points to attachment `filename` of page `pagename`.
-
-        If 'addts' is true, a timestamp with the file's modification time
-        is added, so that browsers reload a changed file.
-    """
-    if htdocs_access(request):
-        # direct file access via webserver
-        timestamp = ''
-        if addts:
-            try:
-                timestamp = '?ts=%s' % os.path.getmtime(
-                    getFilename(request, pagename, filename))
-            except IOError:
-                pass
-
-        url = "%s/%s/attachments/%s%s" % (
-            request.cfg.attachments['url'], wikiutil.quoteWikinameFS(pagename),
-            wikiutil.url_quote(filename), timestamp)
+def attachUrl(request, pagename, filename=None, **kw):
+    # filename is not used yet, but should be used later to make a sub-item url
+    if kw:
+        qs = '?%s' % wikiutil.makeQueryString(kw, want_unicode=False)
     else:
-        # send file via CGI
-        if do not in ['get', 'view']:
-            do = 'get'
-
-        url = "%s/%s?action=%s&do=%s&target=%s" % (
-            request.getScriptname(), wikiutil.quoteWikinameURL(pagename),
-            action_name, do, wikiutil.url_quote_plus(filename))
+        qs = ''
+    return "%s/%s%s" % (request.getScriptname(), wikiutil.quoteWikinameURL(pagename), qs)
+    
+def getAttachUrl(pagename, filename, request, addts=0, escaped=0, do='get', drawing='', upload=False):
+    """ Get URL that points to attachment `filename` of page `pagename`. """
+    if upload:
+        if not drawing:
+            url = attachUrl(request, pagename, filename,
+                            rename=filename, action=action_name)
+        else:
+            url = attachUrl(request, pagename, filename,
+                            rename=filename, drawing=drawing, action=action_name)
+    else:
+        if not drawing:
+            url = attachUrl(request, pagename, filename,
+                            target=filename, action=action_name, do=do)
+        else:
+            url = attachUrl(request, pagename, filename,
+                            drawing=drawing, action=action_name)
     if escaped:
         url = wikiutil.escape(url)
     return url
 
-def getAttachUploadUrl(pagename, filename, request, addts=0, escaped=0):
-    """ Get URL that points to attachment `filename` of page `pagename` upload url.
-    """
-    if htdocs_access(request):
-        # direct file access via webserver - we don't support uploading files,
-        # so just fake some return value:
-        return getAttachUrl(pagename, filename, request, addts=addts, escaped=escaped)
-    else:
-        url = "%s/%s?action=%s&rename=%s" % (
-            request.getScriptname(), wikiutil.quoteWikinameURL(pagename),
-            action_name, wikiutil.url_quote_plus(filename))
-    if escaped:
-        url = wikiutil.escape(url)
-    return url
 
 def getIndicator(request, pagename):
     """ Get an attachment indicator for a page (linked clip image) or
@@ -150,13 +116,12 @@
     if not files:
         return ''
 
+    fmt = request.formatter
     attach_count = _('[%d attachments]') % len(files)
     attach_icon = request.theme.make_icon('attach', vars={'attach_count': attach_count})
-    attach_link = wikiutil.link_tag(request,
-        "%s?action=AttachFile" % wikiutil.quoteWikinameURL(pagename),
-        attach_icon,
-        request.formatter, rel='nofollow')
-
+    attach_link = (fmt.url(1, attachUrl(request, pagename, action=action_name), rel='nofollow') +
+                   attach_icon +
+                   fmt.url(0))
     return attach_link
 
 
@@ -192,7 +157,7 @@
     if os.path.isdir(attach_dir):
         files = os.listdir(attach_dir)
     page = Page(request, pagename)
-    link = page.url(request, {'action': 'AttachFile'})
+    link = page.url(request, {'action': action_name})
     attach_info = _('There are <a href="%(link)s">%(count)s attachment(s)</a> stored for this page.') % {
         'count': len(files),
         'link': wikiutil.escape(link)
@@ -294,6 +259,7 @@
 
 def _build_filelist(request, pagename, showheader, readonly, mime_type='*'):
     _ = request.getText
+    fmt = request.html_formatter
 
     # access directory
     attach_dir = getAttachDir(request, pagename)
@@ -328,54 +294,66 @@
             fsize = "%.1f" % (float(st.st_size) / 1024)
             fmtime = request.user.getFormattedDateTime(st.st_mtime)
             baseurl = request.getScriptname()
-            action = action_name
-            urlpagename = wikiutil.quoteWikinameURL(pagename)
-            urlfile = wikiutil.url_quote_plus(file)
-
             base, ext = os.path.splitext(file)
-            get_url = getAttachUrl(pagename, file, request, escaped=1)
             escaped_fname = wikiutil.escape(file)
-            parmdict = {'baseurl': baseurl, 'urlpagename': urlpagename, 'action': action,
-                        'urlfile': urlfile, 'label_del': label_del,
-                        'label_move': label_move,
-                        'base': base, 'label_edit': label_edit,
-                        'label_view': label_view,
-                        'label_unzip': label_unzip,
-                        'label_install': label_install,
-                        'get_url': get_url, 'label_get': label_get,
+            parmdict = {'baseurl': baseurl,
+                        'base': base,
                         'file': escaped_fname,
                         'fsize': fsize,
                         'fmtime': fmtime,
                         'pagename': pagename}
 
-            del_link = ''
             if request.user.may.delete(pagename) and not readonly:
-                del_link = '<a href="%(baseurl)s/%(urlpagename)s' \
-                    '?action=%(action)s&amp;do=del&amp;target=%(urlfile)s">%(label_del)s</a>&nbsp;| ' % parmdict
+                del_link = (fmt.url(1, getAttachUrl(pagename, file, request, do='del')) +
+                            fmt.text(label_del) +
+                            fmt.url(0) +
+                            fmt.rawHTML('&nbsp;| '))
+            else:
+                del_link = ''
+
             if request.user.may.delete(pagename) and not readonly:
-                move_link = '<a href="%(baseurl)s/%(urlpagename)s' \
-                    '?action=%(action)s&amp;do=move&amp;target=%(urlfile)s">%(label_move)s</a>&nbsp;| ' % parmdict
+                move_link = (fmt.url(1, getAttachUrl(pagename, file, request, do='move')) +
+                             fmt.text(label_move) +
+                             fmt.url(0) +
+                             fmt.rawHTML('&nbsp;| '))
             else:
                 move_link = ''
+
             if ext == '.draw':
-                viewlink = '<a href="%(baseurl)s/%(urlpagename)s?action=%(action)s&amp;drawing=%(base)s">%(label_edit)s</a>' % parmdict
+                view_link = (fmt.url(1, getAttachUrl(pagename, file, request, drawing=parmdict['base'])) +
+                             fmt.text(label_edit) +
+                             fmt.url(0))
             else:
-                viewlink = '<a href="%(baseurl)s/%(urlpagename)s?action=%(action)s&amp;do=view&amp;target=%(urlfile)s">%(label_view)s</a>' % parmdict
+                view_link = (fmt.url(1, getAttachUrl(pagename, file, request, do='view')) +
+                             fmt.text(label_view) +
+                             fmt.url(0))
 
             is_zipfile = zipfile.is_zipfile(os.path.join(attach_dir, file).encode(config.charset))
             if is_zipfile:
                 is_package = packages.ZipPackage(request, os.path.join(attach_dir, file).encode(config.charset)).isPackage()
                 if is_package and request.user.isSuperUser():
-                    viewlink += ' | <a href="%(baseurl)s/%(urlpagename)s?action=%(action)s&amp;do=install&amp;target=%(urlfile)s">%(label_install)s</a>' % parmdict
+                    view_link += (' | ' + 
+                                  fmt.url(1, getAttachUrl(pagename, file, request, do='install')) +
+                                  fmt.text(label_install) +
+                                  fmt.url(0))
                 elif (not is_package and mt.minor == 'zip' and request.user.may.read(pagename) and request.user.may.delete(pagename)
                       and request.user.may.write(pagename)):
-                    viewlink += ' | <a href="%(baseurl)s/%(urlpagename)s?action=%(action)s&amp;do=unzip&amp;target=%(urlfile)s">%(label_unzip)s</a>' % parmdict
+                    view_link += (' | ' + 
+                                  fmt.url(1, getAttachUrl(pagename, file, request, do='unzip')) +
+                                  fmt.text(label_unzip) +
+                                  fmt.url(0))
 
-            parmdict['viewlink'] = viewlink
+            get_link = (fmt.url(1, getAttachUrl(pagename, file, request)) +
+                        fmt.text(label_get) +
+                        fmt.url(0) +
+                        fmt.rawHTML('&nbsp;| '))
+
+            parmdict['viewlink'] = view_link
             parmdict['del_link'] = del_link
             parmdict['move_link'] = move_link
-            html += ('<li>[%(del_link)s%(move_link)s'
-                '<a href="%(get_url)s">%(label_get)s</a>&nbsp;| %(viewlink)s]'
+            parmdict['get_link'] = get_link
+
+            html += ('<li>[%(del_link)s%(move_link)s%(get_link)s%(viewlink)s]'
                 ' (%(fmtime)s, %(fsize)s KB) [[attachment:%(file)s]]</li>') % parmdict
         html += "</ul>"
     else:
@@ -429,17 +407,10 @@
 
 def send_link_rel(request, pagename):
     files = _get_files(request, pagename)
-    if len(files) > 0 and not htdocs_access(request):
-        scriptName = request.getScriptname()
-        pagename_quoted = wikiutil.quoteWikinameURL(pagename)
-
-        for fname in files:
-            url = "%s/%s?action=%s&do=view&target=%s" % (
-                scriptName, pagename_quoted,
-                action_name, wikiutil.url_quote_plus(fname))
-
-            request.write(u'<link rel="Appendix" title="%s" href="%s">\n' % (
-                wikiutil.escape(fname), wikiutil.escape(url)))
+    for fname in files:
+        url = getAttachUrl(pagename, fname, request, do='view', escaped=1)
+        request.write(u'<link rel="Appendix" title="%s" href="%s">\n' % (
+                      wikiutil.escape(fname), url))
 
 
 def send_hotdraw(pagename, request):
@@ -450,21 +421,14 @@
     basename = request.form['drawing'][0]
     drawpath = getAttachUrl(pagename, basename + '.draw', request, escaped=1)
     pngpath = getAttachUrl(pagename, basename + '.png', request, escaped=1)
-    querystr = {'action': 'AttachFile', 'ts': now}
-    querystr = wikiutil.escape(wikiutil.makeQueryString(querystr))
-    pagelink = '%s/%s?%s' % (request.getScriptname(), wikiutil.quoteWikinameURL(pagename), querystr)
+    pagelink = attachUrl(request, pagename, '', action=action_name, ts=now)
     helplink = Page(request, "HelpOnActions/AttachFile").url(request)
-    querystr = {'action': 'AttachFile', 'do': 'savedrawing'}
-    querystr = wikiutil.escape(wikiutil.makeQueryString(querystr))
-    savelink = '%s/%s?%s' % (request.getScriptname(), wikiutil.quoteWikinameURL(pagename), querystr)
+    savelink = attachUrl(request, pagename, '', action=action_name, do='savedrawing')
     #savelink = Page(request, pagename).url(request) # XXX include target filename param here for twisted
                                            # request, {'savename': request.form['drawing'][0]+'.draw'}
     #savelink = '/cgi-bin/dumpform.bat'
 
-    if htdocs_access(request):
-        timestamp = '?ts=%s' % now
-    else:
-        timestamp = '&amp;ts=%s' % now
+    timestamp = '&amp;ts=%s' % now
 
     request.write('<h2>' + _("Edit drawing") + '</h2>')
     request.write("""
@@ -723,8 +687,6 @@
     filename = request.form['filename'][0]
     filecontent = request.form['filepath'][0]
 
-    # there should be no difference in filename parsing with or without
-    # htdocs_access, cause the filename param is used
     basepath, basename = os.path.split(filename)
     basename, ext = os.path.splitext(basename)
 
@@ -828,7 +790,7 @@
         return # error msg already sent in _access_file
 
     # move file
-    d = {'action': 'AttachFile',
+    d = {'action': action_name,
          'baseurl': request.getScriptname(),
          'do': 'attachment_move',
          'ticket': wikiutil.createTicket(request),
@@ -921,8 +883,8 @@
             msg = _("Attachment '%(filename)s' installed.") % {'filename': wikiutil.escape(target)}
         else:
             msg = _("Installation of '%(filename)s' failed.") % {'filename': wikiutil.escape(target)}
-        if package.msg != "":
-            msg += "<br><pre>" + wikiutil.escape(package.msg) + "</pre>"
+        if package.msg:
+            msg += "<br><pre>%s</pre>" % wikiutil.escape(package.msg)
     else:
         msg = _('The file %s is not a MoinMoin package file.') % wikiutil.escape(target)
 
@@ -1013,6 +975,7 @@
 
 def send_viewfile(pagename, request):
     _ = request.getText
+    fmt = request.html_formatter
 
     filename, fpath = _access_file(pagename, request)
     if not filename:
@@ -1021,14 +984,16 @@
     request.write('<h2>' + _("Attachment '%(filename)s'") % {'filename': filename} + '</h2>')
     # show a download link above the content
     label = _('Download')
-    url = getAttachUrl(pagename, filename, request, escaped=1, do='get')
-    timestamp = htdocs_access(request) and "?%s" % time.time() or ''
-    request.write('<a href="%s%s">%s</a><br><br>' % (url, timestamp, label))
+    link = (fmt.url(1, getAttachUrl(pagename, filename, request, do='get')) +
+            fmt.text(label) +
+            fmt.url(0))
+    request.write('%s<br><br>' % link)
 
     mt = wikiutil.MimeType(filename=filename)
     if mt.major == 'image':
-        request.write('<img src="%s%s" alt="%s">' % (
-            getAttachUrl(pagename, filename, request, escaped=1), timestamp, wikiutil.escape(filename, 1)))
+        request.write('<img src="%s" alt="%s">' % (
+            getAttachUrl(pagename, filename, request, escaped=1),
+            wikiutil.escape(filename, 1)))
         return
     elif mt.major == 'text':
         ext = os.path.splitext(filename)[1]
@@ -1077,8 +1042,10 @@
     from MoinMoin.macro.EmbedObject import EmbedObject
     if mt is None:
         request.write('<p>' + _("Unknown file type, cannot display this attachment inline.") + '</p>')
-        request.write('For using an external program follow this link <a href="%s">%s</a>' % (
-             getAttachUrl(pagename, filename, request, escaped=1), wikiutil.escape(filename)))
+        link = (fmt.url(1, getAttachUrl(pagename, filename, request)) +
+                fmt.text(filename) +
+                fmt.url(0))
+        request.write('For using an external program follow this link %s' % link)
         return
 
     url = getAttachUrl(pagename, filename, request, escaped=1)
--- a/MoinMoin/config/multiconfig.py	Thu Feb 28 17:56:44 2008 +0100
+++ b/MoinMoin/config/multiconfig.py	Thu Feb 28 21:31:18 2008 +0100
@@ -232,7 +232,6 @@
     actions_excluded = ['xmlrpc'] # ['DeletePage', 'AttachFile', 'RenamePage', 'test', ]
     allow_xslt = False
     antispam_master_url = "http://master.moinmo.in/?action=xmlrpc2"
-    attachments = None # {'dir': path, 'url': url-prefix}
     auth = [authmodule.MoinLogin()]
     # default to http and xmlrpc_applytoken to get old semantics
     # xmlrpc_applytoken shall be removed once that code is changed
--- a/MoinMoin/formatter/text_html.py	Thu Feb 28 17:56:44 2008 +0100
+++ b/MoinMoin/formatter/text_html.py	Thu Feb 28 21:31:18 2008 +0100
@@ -628,7 +628,7 @@
                 title = "attachment:%s" % url
                 css = 'attachment'
             else:
-                target = AttachFile.getAttachUploadUrl(pagename, fname, self.request)
+                target = AttachFile.getAttachUrl(pagename, fname, self.request, upload=True)
                 title = _('Upload new attachment "%(filename)s"') % {'filename': wikiutil.escape(fname)}
                 css = 'attachment nonexistent'
             return self.url(on, target, css=css, title=title)
@@ -655,14 +655,8 @@
                       'filename': wikiutil.escape(fname)}
             img = self.icon('attachimg')
             css = 'nonexistent'
-            return wikiutil.link_tag(
-                self.request,
-                ('%s?action=AttachFile&rename=%s' %
-                 (wikiutil.quoteWikinameURL(pagename),
-                  wikiutil.url_quote_plus(fname))),
-                img,
-                title=title,
-                css_class=css)
+            target = AttachFile.getAttachUrl(pagename, fname, self.request, upload=True)
+            return self.url(1, target, css=css, title=title) + img + self.url(0)
 
     def attachment_drawing(self, url, text, **kw):
         _ = self.request.getText
@@ -681,21 +675,14 @@
                 fname, filename = gfname, gfilename
 
         # check whether attachment exists, possibly point to upload form
+        drawing_url = AttachFile.getAttachUrl(pagename, fname, self.request, drawing=drawing, upload=True)
         if not exists:
             linktext = _('Create new drawing "%(filename)s (opens in new window)"')
-            return wikiutil.link_tag(
-                self.request,
-                ('%s?action=AttachFile&rename=%s%s' %
-                 (wikiutil.quoteWikinameURL(pagename),
-                  wikiutil.url_quote_plus(fname),
-                  drawing and ('&drawing=%s' % wikiutil.url_quote(drawing)) or '')),
-                linktext % {'filename': self.text(fname)})
+            return (self.url(1, drawing_url) +
+                    self.text(linktext % {'filename': fname}) +
+                    self.url(0))
 
         mappath = AttachFile.getFilename(self.request, pagename, drawing + u'.map')
-        edit_link = ('%s?action=AttachFile&rename=%s&drawing=%s' % (
-            wikiutil.quoteWikinameURL(pagename),
-            wikiutil.url_quote_plus(fname),
-            wikiutil.url_quote(drawing)))
 
         # check for map file
         if os.path.exists(mappath):
@@ -714,23 +701,18 @@
                 map = re.sub('href\s*=\s*"((?!%TWIKIDRAW%).+?)"', r'href="\1" alt="\1" title="\1"', map)
                 # add in edit links plus alt and title attributes
                 alt = title = _('Edit drawing %(filename)s (opens in new window)') % {'filename': self.text(fname)}
-                map = map.replace('%TWIKIDRAW%"', '%s" alt="%s" title="%s"' % (edit_link, alt, title))
+                map = map.replace('%TWIKIDRAW%"', '%s" alt="%s" title="%s"' % (drawing_url, alt, title))
                 # unxml, because 4.01 concrete will not validate />
                 map = map.replace('/>', '>')
                 alt = title = _('Clickable drawing: %(filename)s') % {'filename': self.text(fname)}
-                return (map + self.image(
-                    alt=alt,
-                    title=title,
-                    src=AttachFile.getAttachUrl(pagename, filename, self.request, addts=1),
-                    usemap='#'+mapid, css="drawing"))
+                src = AttachFile.getAttachUrl(pagename, filename, self.request, addts=1)
+                return (map + self.image(alt=alt, title=title, src=src, usemap='#'+mapid, css="drawing"))
         else:
             alt = title = _('Edit drawing %(filename)s (opens in new window)') % {'filename': self.text(fname)}
-            return wikiutil.link_tag(self.request,
-                                     edit_link,
-                                     self.image(alt=alt,
-                                                title=title,
-                                                src=AttachFile.getAttachUrl(pagename, filename, self.request, addts=1), css="drawing"),
-                                     title=title)
+            src = AttachFile.getAttachUrl(pagename, filename, self.request, addts=1)
+            return (self.url(1, drawing_url) +
+                    self.image(alt=alt, title=title, src=src, css="drawing") +
+                    self.url(0))
 
 
     # Text ##############################################################
@@ -1405,3 +1387,4 @@
 
     def sanitize_to_id(self, text):
         return wikiutil.anchor_name_from_text(text)
+
--- a/MoinMoin/macro/EmbedObject.py	Thu Feb 28 17:56:44 2008 +0100
+++ b/MoinMoin/macro/EmbedObject.py	Thu Feb 28 21:31:18 2008 +0100
@@ -209,20 +209,21 @@
 
     def render(self):
         _ = self._
+        fmt = self.formatter
 
         if not self.target:
             msg = _('Not enough arguments given to EmbedObject macro! Try <<EmbedObject(attachment [,width=width] [,height=height] [,alt=alternate Text])>>')
-            return "%s%s%s" % (self.formatter.sysmsg(1), self.formatter.text(msg), self.formatter.sysmsg(0))
+            return "%s%s%s" % (fmt.sysmsg(1), fmt.text(msg), fmt.sysmsg(0))
 
         if not self._is_URL(self.target):
-            pagename, fname = AttachFile.absoluteName(self.target, self.formatter.page.page_name)
+            pagename, fname = AttachFile.absoluteName(self.target, fmt.page.page_name)
 
             if not AttachFile.exists(self.request, pagename, fname):
-                linktext = _('Upload new attachment "%(filename)s"')
-                return wikiutil.link_tag(self.request, ('%s?action=AttachFile&rename=%s' % (
-                                                         wikiutil.quoteWikinameURL(pagename),
-                                                         wikiutil.url_quote_plus(fname))),
-                                                         linktext % {'filename': fname})
+                linktext = _('Upload new attachment "%(filename)s"') % {'filename': fname}
+                target = AttachFile.getAttachUrl(pagename, fname, self.request, upload=True)
+                return (fmt.url(1, target) +
+                        fmt.text(linktext) +
+                        fmt.url(0))
 
             url = AttachFile.getAttachUrl(pagename, fname, self.request)
 
@@ -236,7 +237,7 @@
                 url = wikiutil.escape(self.target)
 
         # XXX Should better use formatter.embed if available?
-        return self.macro.formatter.rawHTML(self.embed(mt, url))
+        return fmt.rawHTML(self.embed(mt, url))
 
 def execute(macro, args):
     return EmbedObject(macro, args).render()