def visit_image(self, node): """ Need to intervene in the case of inline images. We need MoinMoin to give us the actual src line to the image and then we can feed this to the default html4css1 writer. NOTE: Since the writer can't "open" this image the scale attribute doesn't work without directly specifying the height or width (or both). TODO: Need to handle figures similarly. """ uri = node['uri'].lstrip() prefix = '' # assume no prefix attach_name = uri if ':' in uri: prefix = uri.split(':', 1)[0] attach_name = uri.split(':', 1)[1] # if prefix isn't URL, try to display in page if not prefix.lower() in ('file', 'http', 'https', 'ftp'): if not AttachFile.exists(self.request, self.request.page.page_name, attach_name): # Attachment doesn't exist, MoinMoin should process it if prefix == '': prefix = 'attachment:' self.process_wiki_text("{{%s%s}}" % (prefix, attach_name)) self.wiki_text = self.fixup_wiki_formatting(self.wiki_text) self.add_wiki_markup() # Attachment exists, get a link to it. # create the url node['uri'] = AttachFile.getAttachUrl(self.request.page.page_name, attach_name, self.request, addts=1) if not node.hasattr('alt'): node['alt'] = node.get('name', uri) html4css1.HTMLTranslator.visit_image(self, node)
def gedit_drawing(self, url, text, **kw): # This is called for displaying a drawing image by gui editor. _ = self.request.getText # TODO: this 'text' argument is kind of superfluous, replace by using alt=... kw arg # ToDo: make this clickable for the gui editor if 'alt' not in kw or not kw['alt']: kw['alt'] = text # we force the title here, needed later for html>wiki converter kw['title'] = "drawing:%s" % wikiutil.quoteWikinameURL(url) pagename, drawing = AttachFile.absoluteName(url, self.page.page_name) containername = wikiutil.taintfilename(drawing) drawing_url = AttachFile.getAttachUrl(pagename, containername, self.request) ci = AttachFile.ContainerItem(self.request, pagename, containername) if not ci.exists(): title = _( 'Create new drawing "%(filename)s (opens in new window)"') % { 'filename': self.text(containername) } img = self.icon( 'attachimg' ) # TODO: we need a new "drawimg" in similar grey style and size css = 'nonexistent' return self.url(1, drawing_url, css=css, title=title) + img + self.url(0) kw['src'] = ci.member_url('drawing.png') return self.image(**kw)
def xmlrpc_putAttachment(self, pagename, attachname, data): """ Store <data> as content of attachment <attachname> of page <pagename>. @param pagename: pagename (utf-8) @param attachname: attachment name (utf-8) @param data: file data (base64) @rtype: bool @return: True if attachment was successfully stored """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() # also check ACLs if not self.request.user.may.write(pagename): return xmlrpclib.Fault(1, "You are not allowed to edit this page") attachname = wikiutil.taintfilename(self._instr(attachname)) filename = AttachFile.getFilename(self.request, pagename, attachname) if os.path.exists(filename) and not os.path.isfile(filename): return self.noSuchPageFault() open(filename, 'wb+').write(data.data) AttachFile._addLogEntry(self.request, 'ATTNEW', pagename, attachname) return xmlrpclib.Boolean(1)
def test_attachment(self): page_name = u'TestAttachment' self.pages[page_name] = 'some text' # Moin search must search this page filename = "AutoCreatedSillyAttachmentForSearching.png" data = "Test content" filecontent = StringIO.StringIO(data) result = self.search(filename) found_attachments = set([(hit.page_name, hit.attachment) for hit in result.hits]) assert not found_attachments try: create_page(self.request, page_name, self.pages[page_name]) AttachFile.add_attachment(self.request, page_name, filename, filecontent, True) append_page(self.request, page_name, '[[attachment:%s]]' % filename) self._index_update() result = self.search(filename) found_attachments = set([(hit.page_name, hit.attachment) for hit in result.hits]) assert (page_name, '') in found_attachments assert 1 <= len(found_attachments) <= 2 # Note: moin search returns (page_name, '') as only result # xapian search returns 2 results: (page_name, '') and (page_name, filename) # TODO: make behaviour the same, if possible finally: nuke_page(self.request, page_name) del self.pages[page_name] self._index_update() result = self.search(filename) found_attachments = set([(hit.page_name, hit.attachment) for hit in result.hits]) assert not found_attachments
def xmlrpc_putAttachment(self, pagename, attachname, data): """ Set attachname associated with pagename to data @param pagename: pagename (utf-8) @param attachname: attachment name (utf-8) @param data: file data (base64) @rtype boolean @return True if attachment was set """ pagename = self._instr(pagename) # User may read page? if not self.request.user.may.read(pagename): return self.notAllowedFault() # also check ACLs if not self.request.user.may.write(pagename): return xmlrpclib.Fault(1, "You are not allowed to edit this page") attachname = wikiutil.taintfilename(attachname) filename = AttachFile.getFilename(self.request, pagename, attachname) if os.path.exists(filename) and not os.path.isfile(filename): return self.noSuchPageFault() open(filename, 'wb+').write(data.data) AttachFile._addLogEntry(self.request, 'ATTNEW', pagename, filename) return xmlrpclib.Boolean(1)
def test_cache_key_attachment(self): request = self.request pagename = self.pagename attachname = 'foo.txt' become_trusted(request) create_page(request, pagename, u"Foo!") AttachFile.add_attachment(request, pagename, attachname, "Test content1", True) result1 = cache.key(request, itemname=pagename, attachname=attachname, secret='bar') result2 = cache.key(request, itemname=pagename, attachname=attachname, secret='baz') assert result1 # not empty assert result1 != result2 # different for different secret # test below does not work, because mtime is often same, inode can be same due to how add_attachment # works, file size is same, attachment name is same, wikiname/pagename is same. # In practice, this should rather rarely cause problems: #AttachFile.add_attachment(request, pagename, attachname, "Test content2", True) #result3 = cache.key(request, itemname=pagename, attachname=attachname, secret='baz') #assert result3 != result2 # different for different content AttachFile.add_attachment(request, pagename, attachname, "Test content33333", True) result4 = cache.key(request, itemname=pagename, attachname=attachname, secret='baz') assert len(result4) == len(result2) # same length of key for different input lengths nuke_page(request, pagename)
def attachment_inlined(self, url, text, **kw): from MoinMoin.action import AttachFile import os _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) fpath = AttachFile.getFilename(self.request, pagename, fname) ext = os.path.splitext(filename)[1] Parser = wikiutil.getParserForExtension(self.request.cfg, ext) if Parser is not None: try: content = file(fpath, 'r').read() # Try to decode text. It might return junk, but we don't # have enough information with attachments. content = wikiutil.decodeUnknownInput(content) if '.csv' in getattr(Parser, 'extensions', list()): colorizer = Parser(content, self.request, filename=filename, format_args=kw.get('format_args', '')) else: colorizer = Parser(content, self.request, filename=filename) colorizer.format(self) except IOError: pass return (self.attachment_link(1, url) + self.text(text) + self.attachment_link(0))
def attachment_inlined(self, url, text, **kw): from MoinMoin.action import AttachFile import os _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) fpath = AttachFile.getFilename(self.request, pagename, fname) ext = os.path.splitext(filename)[1] Parser = wikiutil.getParserForExtension(self.request.cfg, ext) if Parser is not None: try: # rU: universal newline support so that even a \r is considered a valid line separator. # CSV exported by office (on Mac?) has \r line separators. content = file(fpath, 'rU').read() # Try to decode text. It might return junk, but we don't # have enough information with attachments. content = wikiutil.decodeUnknownInput(content) colorizer = Parser(content, self.request, filename=filename) colorizer.format(self) except IOError: pass return (self.attachment_link(1, url) + self.text(text) + self.attachment_link(0))
def attachment_inlined(self, url, text, **kw): from MoinMoin.action import AttachFile import os _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) fpath = AttachFile.getFilename(self.request, pagename, fname) ext = os.path.splitext(filename)[1] Parser = wikiutil.getParserForExtension(self.request.cfg, ext) if Parser is not None: try: content = file(fpath, "r").read() # Try to decode text. It might return junk, but we don't # have enough information with attachments. content = wikiutil.decodeUnknownInput(content) colorizer = Parser(content, self.request, filename=filename) colorizer.format(self) except IOError: pass self.attachment_link(1, url) self.text(text) self.attachment_link(0) return ""
def _index_page(self, writer, page, update): """ Index a page - assumes that the write lock is acquired @arg writer: the index writer object @arg page: a page object @arg update: False = index in any case, True = index only when changed """ pagename = page.page_name request = page.request mtime = page.mtime_usecs() if update: query = BooleanQuery() query.add(TermQuery(Term("pagename", pagename)), True, False) query.add(TermQuery(Term("attachment", "")), True, False) docs = self._search(query) updated = len(docs) == 0 or mtime > int(docs[0].get('mtime')) else: updated = True request.log("%s %r" % (pagename, updated)) if updated: d = document.Document() d.add(document.Keyword('pagename', pagename)) d.add(document.Keyword('mtime', str(mtime))) d.add(document.Keyword('attachment', '')) # this is a real page, not an attachment d.add(document.Text('title', pagename, store=False)) d.add(document.Text('text', page.get_raw_body(), store=False)) links = page.getPageLinks(request) t = document.Text('links', '', store=False) t.stringVal = links d.add(t) d.add(document.Text('link_text', ' '.join(links), store=False)) writer.addDocument(d) from MoinMoin.action import AttachFile attachments = AttachFile._get_files(request, pagename) for att in attachments: filename = AttachFile.getFilename(request, pagename, att) mtime = wikiutil.timestamp2version(os.path.getmtime(filename)) if update: query = BooleanQuery() query.add(TermQuery(Term("pagename", pagename)), True, False) query.add(TermQuery(Term("attachment", att)), True, False) docs = self._search(query) updated = len(docs) == 0 or mtime > int(docs[0].get('mtime')) else: updated = True request.log("%s %s %r" % (pagename, att, updated)) if updated: att_content = self.contentfilter(filename) d = document.Document() d.add(document.Keyword('pagename', pagename)) d.add(document.Keyword('mtime', str(mtime))) d.add(document.Keyword('attachment', att)) # this is an attachment, store its filename d.add(document.Text('title', att, store=False)) # the filename is the "title" of an attachment d.add(document.Text('text', att_content, store=False)) writer.addDocument(d)
def attachment_drawing(self, url, text, **kw): _ = self.request.getText pagename = self.page.page_name image = url + u'.png' fname = wikiutil.taintfilename(image) fpath = AttachFile.getFilename(self.request, pagename, fname) return self.image( title="drawing:%s" % wikiutil.quoteWikinameURL(url), src=AttachFile.getAttachUrl(pagename, image, self.request, addts=1))
def attachment_image(self, url, **kw): _ = self.request.getText # we force the title here, needed later for html>wiki converter kw['title'] = "attachment:%s" % wikiutil.quoteWikinameURL(url) pagename = self.page.page_name if '/' in url: pagename, target = AttachFile.absoluteName(url, pagename) url = url.split('/')[-1] kw['src'] = AttachFile.getAttachUrl(pagename, url, self.request, addts=1) return self.image(**kw)
def nuke_page(request, pagename): """ completely delete a page, everything in the pagedir """ attachments = AttachFile._get_files(request, pagename) for attachment in attachments: AttachFile.remove_attachment(request, pagename, attachment) page = PageEditor(request, pagename, do_editor_backup=False) page.deletePage() # really get rid of everything there: fpath = page.getPagePath(check_create=0) shutil.rmtree(fpath, True)
def attachment_link(self, on, url=None, **kw): assert on in (0, 1, False, True) # make sure we get called the new way, not like the 1.5 api was # we do not output a "upload link" when outputting docbook if on: pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) target = AttachFile.getAttachUrl(pagename, filename, self.request) return self.url(1, target, title="attachment:%s" % url) else: return self.url(0)
def save(self): request = self.request _ = request.getText if not wikiutil.checkTicket(request, request.args.get('ticket', '')): return _( 'Please use the interactive user interface to use action %(actionname)s!' ) % { 'actionname': 'anywikidraw.save' } pagename = self.pagename target = self.target if not request.user.may.write(pagename): return _('You are not allowed to save a drawing on this page.') if not target: return _("Empty target name given.") file_upload = request.files.get('filepath') if not file_upload: # This might happen when trying to upload file names # with non-ascii characters on Safari. return _( "No file content. Delete non ASCII characters from the file name and try again." ) filename = request.form['filename'] basepath, basename = os.path.split(filename) basename, ext = os.path.splitext(basename) ci = AttachFile.ContainerItem(request, pagename, target) filecontent = file_upload.stream content_length = None if ext == '.svg': # AnyWikiDraw POSTs this first AttachFile._addLogEntry(request, 'ATTDRW', pagename, target) ci.truncate() filecontent = filecontent.read( ) # read file completely into memory filecontent = filecontent.replace("\r", "") elif ext == '.map': # touch attachment directory to invalidate cache if new map is saved attach_dir = AttachFile.getAttachDir(request, pagename) os.utime(attach_dir, None) filecontent = filecontent.read( ) # read file completely into memory filecontent = filecontent.strip() else: #content_length = file_upload.content_length # XXX gives -1 for wsgiref :( If this is fixed, we could use the file obj, # without reading it into memory completely: filecontent = filecontent.read() if filecontent: ci.put('drawing' + ext, filecontent, content_length)
def addAttachment(self, name, content): """add image to attachment""" if os.path.splitext(name)[1].lower() not in \ ['.' + x for x in self.image_extenstions]: name += '.jpg' # if the url didn't contain a image extention AttachFile.add_attachment(self.request, self.pagename, name, content, True) return wikiutil.taintfilename(name)
def attachment_link(self, url, text, **kw): _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) fpath = AttachFile.getFilename(self.request, pagename, fname) target = AttachFile.getAttachUrl(pagename, filename, self.request) if not os.path.exists(fpath): return self.text("[attachment:%s]" % url) else: return (self.url(1, target, title="attachment:%s" % url) + self.text(text) + self.url(0))
def attachment_image(self, url, **kw): _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) fpath = AttachFile.getFilename(self.request, pagename, fname) if not os.path.exists(fpath): return self.text("[attachment:%s]" % url) else: return self.image( title="attachment:%s" % url, src=AttachFile.getAttachUrl(pagename, filename, self.request, addts=1))
def execute(pagename, request): """ Handle action=IntraFarmCopy """ if not request.user.may.read(pagename): Page(request, pagename).send_page() return # Which local farm wiki - assume team for now to_wiki_url = COPY_TO_WIKI_URL # New page name to_wiki_pagename = '%s%s' % (COPY_TO_PREFIX, pagename) # create page at local wiki if it doesn't exist to_request = ScriptContext(to_wiki_url) # login this user remotely to_uid = user.getUserId(to_request, request.user.name) to_user = user.User(to_request, id=to_uid, name=request.user.name, password=request.user.password, auth_method="moin") to_request.user = to_user try: page = Page(to_request, to_wiki_pagename) except: return action_error(u'Error accessing destination page') if not page.exists(): pe = PageEditor(to_request, to_wiki_pagename) # make initial revision pointer to original try: pe.saveText(u'[[%s:%s]]' % (request.cfg.interwikiname, pagename), 0, comment="Automated IntraFarmCopy pointing to original page") except pe.Unchanged: return action_error(u'Could not save initial page') except pe.AccessDenied: return action_error(u'Could not acquire credentials') # make next revision content of this page try: pe.saveText(Page(request, pagename).get_raw_body(), 0, comment="Automated IntraFarmCopy importing contents from original page at [[%s:%s]]" % (request.cfg.interwikiname, pagename)) except pe.Unchanged: return action_error(u'Could not save destination page text') # send attachments over attachments = AttachFile._get_files(request, pagename) for attachname in attachments: filename = AttachFile.getFilename(request, pagename, attachname) if not os.path.isfile(filename): continue to_filename = AttachFile.getFilename(to_request, to_wiki_pagename, attachname) shutil.copyfile(filename, to_filename) AttachFile._addLogEntry(to_request, 'ATTNEW', to_wiki_pagename, attachname) # redirect user to view new page in other wiki request.http_redirect('%s%s' % (to_wiki_url, to_wiki_pagename)) return else: return action_error(u'Destination page already exists!')
def attachment_link(self, on, url=None, **kw): assert on in ( 0, 1, False, True ) # make sure we get called the new way, not like the 1.5 api was # we do not output a "upload link" when outputting docbook if on: pagename, filename = AttachFile.absoluteName( url, self.page.page_name) fname = wikiutil.taintfilename(filename) target = AttachFile.getAttachUrl(pagename, filename, self.request) return self.url(1, target, title="attachment:%s" % url) else: return self.url(0)
def attachment_drawing(self, url, text, **kw): _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) drawing = fname fname = fname + ".png" filename = filename + ".png" fpath = AttachFile.getFilename(self.request, pagename, fname) if not os.path.exists(fpath): return self.text("{{drawing:%s}}" % url) else: src = AttachFile.getAttachUrl(pagename, filename, self.request, addts=1) return self.image(alt=drawing, src=src, html_class="drawing")
def macro_ThumbnailGallery(macro, page=None, regex=None, height=200, width=None, link=True): _ = macro.request.getText formatter = macro.formatter pagename = page or macro.formatter.page.page_name output = [] if not regex: regex = re.compile(".*\.(jpg|jpeg|png|gif)$") else: regex = re.compile(regex) if not macro.request.user.may.read(pagename): return _('You are not allowed to view attachments of this page.') for attachment in AttachFile._get_files(macro.request, pagename): if regex.match(attachment) is None: continue pagename, filename = AttachFile.absoluteName(attachment, pagename) fname = wikiutil.taintfilename(filename) if width: size, dimension = width, "w" else: size, dimension = height, "h" if AttachFile.exists(macro.request, pagename, fname): url = AttachFile.getAttachUrl(pagename, fname, macro.request, do='get') output.extend([ macro.formatter.url(True, url) if link else "", macro.formatter.image( macro.request.href( pagename, { "target": fname, "action": "Thumbnail", "do": "tc:{},{}".format(size, dimension) })), macro.formatter.url(False) if link else "", " ", ]) return "".join(output)
def attachment_drawing(self, url, text, **kw): # This is called for displaying a clickable drawing image by text_html formatter. # XXX text arg is unused! _ = self.request.getText pagename, drawing = AttachFile.absoluteName(url, self.page.page_name) containername = wikiutil.taintfilename(drawing) drawing_url = AttachFile.getAttachUrl(pagename, containername, self.request, do='modify') ci = AttachFile.ContainerItem(self.request, pagename, containername) if not ci.exists(): title = _('Create new drawing "%(filename)s (opens in new window)"') % {'filename': self.text(containername)} img = self.icon('attachimg') # TODO: we need a new "drawimg" in similar grey style and size css = 'nonexistent' return self.url(1, drawing_url, css=css, title=title) + img + self.url(0) title = _('Edit drawing %(filename)s (opens in new window)') % {'filename': self.text(containername)} kw['src'] = src = ci.member_url('drawing.png') kw['css'] = 'drawing' try: mapfile = ci.get('drawing.map') map = mapfile.read() mapfile.close() map = map.decode(config.charset) except (KeyError, IOError, OSError): map = u'' if map: # we have a image map. inline it and add a map ref to the img tag # we have also to set a unique ID mapid = u'ImageMapOf%s%s' % (self.request.uid_generator(pagename), drawing) map = map.replace(u'%MAPNAME%', mapid) # add alt and title tags to areas map = re.sub(ur'href\s*=\s*"((?!%TWIKIDRAW%).+?)"', ur'href="\1" alt="\1" title="\1"', map) map = map.replace(u'%TWIKIDRAW%"', u'%s" alt="%s" title="%s"' % ( wikiutil.escape(drawing_url, 1), title, title)) # unxml, because 4.01 concrete will not validate /> map = map.replace(u'/>', u'>') title = _('Clickable drawing: %(filename)s') % {'filename': self.text(containername)} if 'title' not in kw: kw['title'] = title if 'alt' not in kw: kw['alt'] = kw['title'] kw['usemap'] = '#'+mapid return self.url(1, drawing_url) + map + self.image(**kw) + self.url(0) else: if 'title' not in kw: kw['title'] = title if 'alt' not in kw: kw['alt'] = kw['title'] return self.url(1, drawing_url) + self.image(**kw) + self.url(0)
def render(self): _ = self.request.getText pagename, attname = AttachFile.absoluteName(self.target, self.formatter.page.page_name) attachment_fname = AttachFile.getFilename(self.request, pagename, attname) if not os.path.exists(attachment_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(attname))), linktext % {'filename': attname}) url = AttachFile.getAttachUrl(pagename, attname, self.request) mime_type, enc = mimetypes.guess_type(attname) if mime_type in ["application/x-shockwave-flash", "application/x-dvi", "application/postscript", "application/pdf", "application/ogg", "application/vnd.visio", "image/x-ms-bmp", "image/svg+xml", "image/tiff", "image/x-photoshop", "audio/mpeg", "audio/midi", "audio/x-wav", "video/fli", "video/mpeg", "video/quicktime", "video/x-msvideo", "chemical/x-pdb", "x-world/x-vrml", ]: return self.embed(mime_type, url) else: msg = 'Not supported mimetype %(mimetype)s ' % {"mimetype": mime_type} return "%s%s%s" % (self.macro.formatter.sysmsg(1), self.macro.formatter.text(msg), self.macro.formatter.sysmsg(0))
def attachment_drawing(self, url, text, **kw): _ = self.request.getText # TODO: this 'text' argument is kind of superfluous, replace by using alt=... kw arg if 'alt' not in kw or not kw['alt']: kw['alt'] = text # we force the title here, needed later for html>wiki converter kw['title'] = "drawing:%s" % wikiutil.quoteWikinameURL(url) pagename = self.page.page_name if '/' in url: pagename, target = AttachFile.absoluteName(url, pagename) url = url.split('/')[-1] url += '.png' kw['src'] = AttachFile.getAttachUrl(pagename, url, self.request, addts=1) return self.image(**kw)
def test_add_attachment(self): """Test if add_attachment() works""" become_trusted(self.request) filename = "AutoCreatedSillyAttachment" create_page(self.request, self.pagename, u"Foo!") AttachFile.add_attachment(self.request, self.pagename, filename, "Test content", True) exists = AttachFile.exists(self.request, self.pagename, filename) nuke_page(self.request, self.pagename) assert exists
def setup_class(self): request = self.request pagename = self.pagename become_trusted(request) self.page = create_page(request, pagename, u"Foo") AttachFile.getAttachDir(request, pagename) test_files = [ ('test.ogg', 'vorbis'), ('test.svg', 'SVG'), ('test.mpg', 'MPG'), ('test.pdf', 'PDF'), ('test.mp3', 'MP3'), ] for filename, filecontent in test_files: AttachFile.add_attachment(request, pagename, filename, filecontent, overwrite=0)
def setup_class(self): request = self.request pagename = self.pagename become_trusted(request) self.page = create_page(request, pagename, u"Foo") AttachFile.getAttachDir(request, pagename) test_files = [ ("test.ogg", "vorbis"), ("test.svg", "SVG"), ("test.mpg", "MPG"), ("test.pdf", "PDF"), ("test.mp3", "MP3"), ] for filename, filecontent in test_files: AttachFile.add_attachment(request, pagename, filename, filecontent, overwrite=0)
def attachment(self, target_and_text, **kw): """ This gets called on attachment URLs """ _ = self._ scheme, fname, text = wikiutil160a.split_wiki(target_and_text) pagename, fname = AttachFile.absoluteName(fname, self.pagename) from_this_page = pagename == self.pagename fname = self._replace(('FILE', pagename, fname)) #fname = wikiutil.url_unquote(fname) #fname = self._replace(('FILE', pagename, fname)) pagename = self._replace(('PAGE', pagename)) if from_this_page: name = fname else: name = "%s/%s" % (pagename, fname) fn_txt = name if text: fn_txt += '|' + text if scheme == 'drawing': return "{{drawing:%s}}" % fn_txt # check for image, and possibly return IMG tag (images are always inlined) if not kw.get('pretty_url', 0) and wikiutil.isPicture(fname): return "{{attachment:%s}}" % fn_txt # inline the attachment if scheme == 'inline': return '{{attachment:%s}}' % fn_txt return '[[attachment:%s]]' % fn_txt
def attachment_link(self, url, text, **kw): _ = self.request.getText pagename = self.page.page_name target = AttachFile.getAttachUrl(pagename, url, self.request) return (self.url(1, target, title="attachment:%s" % wikiutil.quoteWikinameURL(url)) + self.text(text) + self.url(0))
def copypage(self, request, rootdir, pagename): """ quick and dirty! """ pagedir = os.path.join(rootdir, 'pages', wikiutil.quoteWikinameFS(pagename)) os.makedirs(pagedir) # write a "current" file with content "00000001" revstr = '%08d' % 1 cf = os.path.join(pagedir, 'current') file(cf, 'w').write(revstr + '\n') # create a single revision 00000001 revdir = os.path.join(pagedir, 'revisions') os.makedirs(revdir) tf = os.path.join(revdir, revstr) p = Page(request, pagename) text = p.get_raw_body().replace("\n", "\r\n") codecs.open(tf, 'wb', config.charset).write(text) source_dir = AttachFile.getAttachDir(request, pagename) if os.path.exists(source_dir): dest_dir = os.path.join(pagedir, "attachments") os.makedirs(dest_dir) for filename in os.listdir(source_dir): source_file = os.path.join(source_dir, filename) dest_file = os.path.join(dest_dir, filename) shutil.copyfile(source_file, dest_file)
def do_action(self): """ Load """ status = False _ = self._ form = self.form request = self.request comment = form.get('comment', [u''])[0] comment = wikiutil.clean_input(comment) filename = form.get('file__filename__') rename = form.get('rename', [''])[0].strip() if rename: target = rename else: target = filename target = AttachFile.preprocess_filename(target) target = wikiutil.clean_input(target) if target: filecontent = form['file'][0] if hasattr(filecontent, 'read'): # a file-like object filecontent = filecontent.read() # XXX reads complete file into memory! filecontent = wikiutil.decodeUnknownInput(filecontent) self.pagename = target pg = PageEditor(request, self.pagename) try: msg = pg.saveText(filecontent, 0, comment=comment) status = True except pg.EditConflict, e: msg = e.message except pg.SaveError, msg: msg = unicode(msg)
def copypage(self, request, rootdir, pagename): """ quick and dirty! """ pagedir = os.path.join(rootdir, 'pages', wikiutil.quoteWikinameFS(pagename)) os.makedirs(pagedir) # write a "current" file with content "00000001" revstr = '%08d' % 1 cf = os.path.join(pagedir, 'current') file(cf, 'w').write(revstr+'\n') # create a single revision 00000001 revdir = os.path.join(pagedir, 'revisions') os.makedirs(revdir) tf = os.path.join(revdir, revstr) p = Page(request, pagename) text = p.get_raw_body().replace("\n", "\r\n") codecs.open(tf, 'wb', config.charset).write(text) source_dir = AttachFile.getAttachDir(request, pagename) if os.path.exists(source_dir): dest_dir = os.path.join(pagedir, "attachments") os.makedirs(dest_dir) for filename in os.listdir(source_dir): source_file = os.path.join(source_dir, filename) dest_file = os.path.join(dest_dir, filename) shutil.copyfile(source_file, dest_file)
def attachment_list(self): html = AttachFile._build_filelist(self.request, self.page_name, showheader=0, readonly=0) if html: html = u'<div id="attachments">\n%s\n</div>' % html return html
def save(self): request = self.request _ = request.getText if not wikiutil.checkTicket(request, request.args.get('ticket', '')): return _('Please use the interactive user interface to use action %(actionname)s!') % {'actionname': 'anywikidraw.save' } pagename = self.pagename target = self.target if not request.user.may.write(pagename): return _('You are not allowed to save a drawing on this page.') if not target: return _("Empty target name given.") file_upload = request.files.get('filepath') if not file_upload: # This might happen when trying to upload file names # with non-ascii characters on Safari. return _("No file content. Delete non ASCII characters from the file name and try again.") filename = request.form['filename'] basepath, basename = os.path.split(filename) basename, ext = os.path.splitext(basename) ci = AttachFile.ContainerItem(request, pagename, target) filecontent = file_upload.stream content_length = None if ext == '.svg': # AnyWikiDraw POSTs this first AttachFile._addLogEntry(request, 'ATTDRW', pagename, target) ci.truncate() filecontent = filecontent.read() # read file completely into memory filecontent = filecontent.replace("\r", "") elif ext == '.map': # touch attachment directory to invalidate cache if new map is saved attach_dir = AttachFile.getAttachDir(request, pagename) os.utime(attach_dir, None) filecontent = filecontent.read() # read file completely into memory filecontent = filecontent.strip() else: #content_length = file_upload.content_length # XXX gives -1 for wsgiref :( If this is fixed, we could use the file obj, # without reading it into memory completely: filecontent = filecontent.read() if filecontent: ci.put('drawing' + ext, filecontent, content_length)
def render(self): request = self.request _ = request.getText pagename = self.pagename target = self.target if not request.user.may.read(pagename): return _('You are not allowed to view attachments of this page.') if not request.user.may.write(pagename): # note: "recycled" a already existing translated string, so we do not need a new string: return _('You are not allowed to save a drawing on this page.') if not target: return _("Empty target name given.") ci = AttachFile.ContainerItem(request, pagename, target) if ci.exists(): drawurl = ci.member_url('drawing.draw') pngurl = ci.member_url('drawing.png') else: drawurl = 'drawing.draw' pngurl = 'drawing.png' pageurl = request.href(pagename) saveurl = request.href(pagename, action=action_name, do='save', target=target, ticket=wikiutil.createTicket(request)) helpurl = request.href("HelpOnActions/AttachFile") html = """ <p> <applet code="CH.ifa.draw.twiki.TWikiDraw.class" archive="%(htdocs)s/applets/TWikiDrawPlugin/twikidraw.jar" width="640" height="480"> <param name="drawpath" value="%(drawurl)s"> <param name="pngpath" value="%(pngurl)s"> <param name="savepath" value="%(saveurl)s"> <param name="basename" value="%(basename)s"> <param name="viewpath" value="%(pageurl)s"> <param name="helppath" value="%(helpurl)s"> <strong>NOTE:</strong> You need a Java enabled browser to edit the drawing. </applet> </p> """ % dict( htdocs=request.cfg.url_prefix_static, basename=wikiutil.escape(target, 1), drawurl=wikiutil.escape(drawurl, 1), pngurl=wikiutil.escape(pngurl, 1), pageurl=wikiutil.escape(pageurl, 1), saveurl=wikiutil.escape(saveurl, 1), helpurl=wikiutil.escape(helpurl, 1), ) title = "%s %s:%s" % (_("Edit drawing"), pagename, target) request.theme.send_title(title, page=request.page, pagename=pagename) request.write(request.formatter.startContent("content")) request.write(request.formatter.rawHTML(html)) request.write(request.formatter.endContent()) request.theme.send_footer(pagename) request.theme.send_closing_html()
def collectpackage(self, pagelist, fileobject, pkgname="", include_attachments=False): """ Expects a list of pages as an argument, and fileobject to be an open file object, which a zipfile will get written to. @param pagelist: pages to package @param fileobject: open file object to write to @param pkgname: optional file name, to prevent self packaging @rtype: string or None @return: error message, if one happened @rtype: boolean @param include_attachments: True if you want attachments collected """ _ = self.request.getText COMPRESSION_LEVEL = zipfile.ZIP_DEFLATED pages = [] for pagename in pagelist: pagename = wikiutil.normalize_pagename(pagename, self.request.cfg) if pagename: page = Page(self.request, pagename) if page.exists() and self.request.user.may.read(pagename): pages.append(page) if not pages: return (_('No pages like "%s"!') % wikiutil.escape(pagelist)) # Set zipfile output zf = zipfile.ZipFile(fileobject, "w", COMPRESSION_LEVEL) cnt = 0 userid = user.getUserIdentification(self.request) script = [packLine(['MoinMoinPackage', '1']), ] for page in pages: cnt += 1 files = _get_files(self.request, page.page_name) script.append(packLine(["AddRevision", str(cnt), page.page_name, userid, "Created by the PackagePages action."])) timestamp = wikiutil.version2timestamp(page.mtime_usecs()) # avoid getting strange exceptions from zipfile in case of pre-1980 timestamps nineteeneighty = (10 * 365 + 3) * 24 * 3600 # 1970 + 10y + 3d timestamp = max(nineteeneighty, timestamp) # zip can not store timestamps before 1980 zi = zipfile.ZipInfo(filename=str(cnt), date_time=datetime.fromtimestamp(timestamp).timetuple()[:6]) zi.compress_type = COMPRESSION_LEVEL zf.writestr(zi, page.get_raw_body().encode("utf-8")) if include_attachments: for attname in files: if attname != pkgname: cnt += 1 zipname = "%d_attachment" % cnt script.append(packLine(["AddAttachment", zipname, attname, page.page_name, userid, "Created by the PackagePages action."])) filename = AttachFile.getFilename(self.request, page.page_name, attname) zf.write(filename, zipname) script += [packLine(['Print', 'Thank you for using PackagePages!'])] zf.writestr(MOIN_PACKAGE_FILE, u"\n".join(script).encode("utf-8")) zf.close()
def _index_attachment(self, request, connection, pagename, attachmentname, mode='update'): """ Index an attachment @param request: request suitable for indexing @param connection: the Indexer connection object @param pagename: the page name @param attachmentname: the attachment's name @param mode: 'add' = just add, no checks 'update' = check if already in index and update if needed (mtime) """ from MoinMoin.action import AttachFile wikiname = request.cfg.interwikiname or u"Self" itemid = "%s:%s//%s" % (wikiname, pagename, attachmentname) filename = AttachFile.getFilename(request, pagename, attachmentname) # check if the file is still there. as we might be doing queued index updates, # the file could be gone meanwhile... if os.path.exists(filename): mtime = wikiutil.timestamp2version(os.path.getmtime(filename)) doc = self._get_document(connection, itemid, mtime, mode) logging.debug("%r %r %r" % (pagename, attachmentname, doc)) if doc: page = Page(request, pagename) mimetype, att_content = self.contentfilter(filename) fields = {} fields['wikiname'] = wikiname fields['pagename'] = pagename fields['attachment'] = attachmentname fields['mtime'] = str(mtime) fields['revision'] = '0' fields['title'] = '%s/%s' % (pagename, attachmentname) fields['content'] = att_content fields['lang'], fields['stem_lang'] = self._get_languages(page) multivalued_fields = {} multivalued_fields['mimetype'] = [ mt for mt in [mimetype] + mimetype.split('/') ] multivalued_fields['domain'] = self._get_domains(page) self._add_fields_to_document(request, doc, fields, multivalued_fields) try: connection.replace(doc) except xapian.Error, err: logging.error( 'attachment %r (page %r) could not be updated in index: %s' % (attachmentname, pagename, str(err))) else: logging.debug('attachment %r (page %r) updated in index' % (attachmentname, pagename))
def get_attachment_dict(self, page_name): """ Returns a dict of attachments The structure of the dictionary is: { file_name : [file_size, get_url], ... } @param page_name: @rtype: attachments dictionary @return: attachments dictionary """ attach_dir = AttachFile.getAttachDir(self.request, page_name) files = AttachFile._get_files(self.request, page_name) attachments = {} for file in files: fsize = float(os.stat(os.path.join(attach_dir,file).encode(config.charset))[6]) get_url = AttachFile.getAttachUrl(page_name, file, self.request, escaped=1) attachments[file] = [fsize, get_url] return attachments
def test_getAttachUrl(self): """ Tests if AttachFile.getAttachUrl taints a filename """ filename = "<test2.txt>" expect = "rename=_test2.txt_&" result = AttachFile.getAttachUrl(self.pagename, filename, self.request, upload=True) assert expect in result
def packagePages(self, pagelist, filename, function): """ Puts pages from pagelist into filename and calls function on them on installation. """ request = self.request try: os.remove(filename) except OSError: pass # page LanguageSetup needs no packing! existing_pages = [ pagename for pagename in pagelist if Page(request, pagename).exists() and pagename != 'LanguageSetup' ] if not existing_pages: return zf = zipfile.ZipFile(filename, "w", COMPRESSION_LEVEL) script = [ packLine(['MoinMoinPackage', '1']), ] cnt = 0 for pagename in existing_pages: pagename = pagename.strip() page = Page(request, pagename) files = _get_files(request, pagename) for attname in files: cnt += 1 zipname = "%d" % cnt script.append( packLine([ "ReplaceUnderlayAttachment", zipname, attname, pagename ])) attpath = AttachFile.getFilename(request, pagename, attname) zf.write(attpath, zipname) cnt += 1 zipname = "%d" % cnt script.append(packLine([function, zipname, pagename])) timestamp = wikiutil.version2timestamp(page.mtime_usecs()) zi = zipfile.ZipInfo( filename=zipname, date_time=datetime.fromtimestamp(timestamp).timetuple()[:6]) zi.compress_type = COMPRESSION_LEVEL zf.writestr(zi, page.get_raw_body().encode("utf-8")) script += [ packLine([ 'Print', 'Installed MoinMaster page bundle %s.' % os.path.basename(filename) ]) ] zf.writestr(MOIN_PACKAGE_FILE, u"\n".join(script).encode("utf-8")) zf.close()
def attachment_drawing(self, url, text, **kw): # Todo get it to start the drawing editor on a click try: drawing_action = AttachFile.get_action(self.request, url, do='modify') assert drawing_action is not None attachment_drawing = wikiutil.importPlugin(self.request.cfg, 'action', drawing_action, 'gedit_drawing') return attachment_drawing(self, url, text, **kw) except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError, AssertionError): return url
def xmlrpc_deleteAttachment(self, pagename, attachname): """ Deletes attachment <attachname> of page <pagename>. @param pagename: pagename (utf-8) @param attachname: attachment name (utf-8) @rtype: bool @return: True on success """ pagename = self._instr(pagename) if not self.request.user.may.delete(pagename): return xmlrpclib.Fault( 1, 'You are not allowed to delete attachments on this page.') attachname = wikiutil.taintfilename(self._instr(attachname)) filename = AttachFile.getFilename(self.request, pagename, attachname) AttachFile.remove_attachment(self.request, pagename, attachname) return xmlrpclib.Boolean(1)
def key(request, wikiname=None, itemname=None, attachname=None, content=None, secret=None): """ Calculate a (hard-to-guess) cache key. Important key properties: * The key must be hard to guess (this is because do=get does no ACL checks, so whoever got the key [e.g. from html rendering of an ACL protected wiki page], will be able to see the cached content. * The key must change if the (original) content changes. This is because ACLs on some item may change and even if somebody was allowed to see some revision of some item, it does not implicate that he is allowed to see any other revision also. There will be no harm if he can see exactly the same content again, but there could be harm if he could access a revision with different content. If content is supplied, we will calculate and return a hMAC of the content. If wikiname, itemname, attachname is given, we don't touch the content (nor do we read it ourselves from the attachment file), but we just calculate a key from the given metadata values and some metadata we get from the filesystem. Hint: if you need multiple cache objects for the same source content (e.g. thumbnails of different sizes for the same image), calculate the key only once and then add some different prefixes to it to get the final cache keys. @param request: the request object @param wikiname: the name of the wiki (if not given, will be read from cfg) @param itemname: the name of the page @param attachname: the filename of the attachment @param content: content data as unicode object (e.g. for page content or parser section content) @param secret: secret for hMAC calculation (default: use secret from cfg) """ if secret is None: secret = request.cfg.secrets['action/cache'] if content: hmac_data = content elif itemname is not None and attachname is not None: wikiname = wikiname or request.cfg.interwikiname or request.cfg.siteid fuid = filesys.fuid( AttachFile.getFilename(request, itemname, attachname)) hmac_data = u''.join([wikiname, itemname, attachname, repr(fuid)]) else: raise AssertionError('cache_key called with unsupported parameters') hmac_data = hmac_data.encode('utf-8') key = hmac.new(secret, hmac_data).hexdigest() return key
def attachment_image(self, url, **kw): """ Figures out the absolute path to the image and then hands over to the image function. Any title is also handed over, and an additional title suggestion is made based on filename. The image function will use the suggestion if no other text alternative is found. If the file is not found, then a simple text will replace it. """ _ = self.request.getText pagename, filename = AttachFile.absoluteName(url, self.page.page_name) fname = wikiutil.taintfilename(filename) fpath = AttachFile.getFilename(self.request, pagename, fname) if not os.path.exists(fpath): return self.text("{{attachment:%s}}" % url) else: return self.image(src=AttachFile.getAttachUrl(pagename, filename, self.request, addts=1), attachment_title=url, **kw)
def test_add_attachment_for_file_object(self): """Test if add_attachment() works with file like object""" become_trusted(self.request) filename = "AutoCreatedSillyAttachment.png" create_page(self.request, self.pagename, u"FooBar!") data = "Test content" filecontent = StringIO.StringIO(data) AttachFile.add_attachment(self.request, self.pagename, filename, filecontent, True) exists = AttachFile.exists(self.request, self.pagename, filename) path = AttachFile.getAttachDir(self.request, self.pagename) imagef = os.path.join(path, filename) file_size = os.path.getsize(imagef) nuke_page(self.request, self.pagename) assert exists and file_size == len(data)
def attachment_link(self, on, url=None, **kw): assert on in (0, 1, False, True) # make sure we get called the new way, not like the 1.5 api was _ = self.request.getText querystr = kw.get('querystr', {}) assert isinstance(querystr, dict) # new in 1.6, only support dicts if 'do' not in querystr: querystr['do'] = 'view' if on: pagename = self.page.page_name target = AttachFile.getAttachUrl(pagename, url, self.request, do=querystr['do']) return self.url(on, target, title="attachment:%s" % wikiutil.quoteWikinameURL(url)) else: return self.url(on)
def test_cache_key_attachment(self): request = self.request pagename = self.pagename attachname = 'foo.txt' become_trusted(request) create_page(request, pagename, u"Foo!") AttachFile.add_attachment(request, pagename, attachname, "Test content1", True) result1 = cache.key(request, itemname=pagename, attachname=attachname, secret='bar') result2 = cache.key(request, itemname=pagename, attachname=attachname, secret='baz') assert result1 # not empty assert result1 != result2 # different for different secret # test below does not work, because mtime is often same, inode can be same due to how add_attachment # works, file size is same, attachment name is same, wikiname/pagename is same. # In practice, this should rather rarely cause problems: #AttachFile.add_attachment(request, pagename, attachname, "Test content2", True) #result3 = cache.key(request, itemname=pagename, attachname=attachname, secret='baz') #assert result3 != result2 # different for different content AttachFile.add_attachment(request, pagename, attachname, "Test content33333", True) result4 = cache.key(request, itemname=pagename, attachname=attachname, secret='baz') assert len(result4) == len( result2) # same length of key for different input lengths nuke_page(request, pagename)
def macro_Thumbnail(macro, attachment, height=200, width=None, link=True): _ = macro.request.getText formatter = macro.formatter pagename, filename = AttachFile.absoluteName(attachment, formatter.page.page_name) fname = wikiutil.taintfilename(filename) if not macro.request.user.may.read(pagename): return _('You are not allowed to view attachments of this page.') if width: size, dimension = width, "w" else: size, dimension = height, "h" if AttachFile.exists(macro.request, pagename, fname): url = AttachFile.getAttachUrl(pagename, fname, macro.request, do='get') output = [ formatter.url(True, url) if link else "", formatter.image( macro.request.href( pagename, { "target": fname, "action": "Thumbnail", "do": "tc:{},{}".format(size, dimension) })), formatter.url(False) if link else "", ] else: output = [ formatter.span(True, style="color: red"), "No Image: {}".format(attachment), formatter.span(False), ] return "".join(output)
def get_attachment_dict(self, page_name): """ Returns a dict of attachments The structure of the dictionary is: { file_name : [file_size, get_url], ... } @param page_name: @rtype: attachments dictionary @return: attachments dictionary """ attach_dir = AttachFile.getAttachDir(self.request, page_name) files = AttachFile._get_files(self.request, page_name) attachments = {} for file in files: fsize = float( os.stat(os.path.join(attach_dir, file).encode(config.charset))[6]) get_url = AttachFile.getAttachUrl(page_name, file, self.request, escaped=1) attachments[file] = [fsize, get_url] return attachments