def generate_feed(config_agent, req_path, tpl_render): folder_pages_full_path = config_agent.config.get("paths", "pages_path") cache_file_full_path = os.path.join(folder_pages_full_path, ".zw_all_pages_list_cache") buf = cache.get_all_pages_list_from_cache(config_agent) md_list = buf.split() author = config_agent.config.get("main", "maintainer_email") or "Anonymous" e_author = atom.Element(name="author") child = atom.Element(name="name", text=author) e_author.append_children(child) ts = os.stat(cache_file_full_path).st_ctime updated = atom.generate_updated(ts) ts_as_id = "timestamp:" + commons.strutils.md5(updated) feed = atom.Feed(author=e_author, id=ts_as_id, updated=updated, title="Testing Feed Output") for md_file_name in md_list[:100]: req_path = commons.strutils.rstrips(md_file_name, ".md") req_path = commons.strutils.rstrips(req_path, ".markdown") local_full_path = mdutils.req_path_to_local_full_path( req_path, folder_pages_full_path) raw_text = commons.shutils.cat(local_full_path) page_title = mdutils.get_title_by_file_path_in_md( folder_pages_full_path, req_path) static_file_prefix = static_file.get_static_file_prefix_by_local_full_path( config_agent=config_agent, local_full_path=local_full_path, req_path=req_path) view_settings = page.get_view_settings(config_agent) page_content = mdutils.md2html(config_agent=config_agent, req_path=req_path, text=raw_text, static_file_prefix=static_file_prefix, **view_settings) text = cgi.escape(commons.strutils.safestr(page_content)) e_content = atom.Element(name="content", text=text, type="html") if not page_title: continue hash_title_as_id = "md5:" + commons.strutils.md5(page_title) updated = atom.generate_updated(os.stat(local_full_path).st_ctime) entry = atom.Entry(id=hash_title_as_id, title=page_title, updated=updated, content=e_content) feed.append_children(entry) buf = str(feed) return buf
def testConvertToAndFromString(self): entry = atom.Entry() entry.author.append(atom.Author(name=atom.Name(text='js'))) entry.title = atom.Title(text='my test entry') self.assert_(entry.author[0].name.text == 'js') self.assert_(entry.title.text == 'my test entry') new_entry = atom.EntryFromString(entry.ToString()) self.assert_(new_entry.author[0].name.text == 'js') self.assert_(new_entry.title.text == 'my test entry')
def __post(self, author, title, summary, content, category, draft, entryXml): """ to post the content to the server @param author: Author name @type author: String @param title: Title of the content @type title: String @param summary: Summary of the content @type summary: String @param content: Content @type content: String @param draft: Type of the document: @type draft: boolean @param entryXml: extra entry @type entryXml: String @rtype: (Atom Entry, String) @return: entry, httpResponse """ # create/update the atom entry if entryXml == None: entry = atom.Entry() entryUri = self.entryUri else: entry = atom.EntryFromString(entryXml) entryUri = entry.GetEditLink().href entry.author = [atom.Author(text=author)] entry.title = atom.Title(text=title) entry.summary = atom.Summary(text=summary) entry.content = atom.Content(content_type="html", text=unicode(content, "utf-8")) if category != "": entry.category = atom.Category(term=category) if draft: entry.control = atom.Control(draft=atom.Draft(text="yes")) else: entry.control = atom.Control(draft=atom.Draft(text="no")) # setup the http headers for authorisation extraHeaders = {"Slug": title} extraHeaders.update(self.authHeaders) # use POST or PUT depending on whether it is a new entry or an update if entryXml != None: publishFunc = self.atomService.Put else: publishFunc = self.atomService.Post self.__checkNoProxy(entryUri) httpResponse = publishFunc(data=entry, uri=entryUri, extra_headers=extraHeaders) self.__resetProxy() return entry, httpResponse
def __getEntryForDocument(self, queryPath, id): """ @param queryPath: Query to search for the entry @type queryPath: String @param id: Id to be applied to atom feed @type id: String @rtype: ElementTree._Element, or xml_wrapper.ElementWrapper @return entry """ docPath = self.rep.getPathForId(id) # check docPath if docPath.startswith(queryPath): item = self.rep.getItem(docPath) if item.hasHtml: docPath = self.iceContext.fs.splitExt(docPath)[0] + ".htm" title = item.getMeta("title") try: title = title.decode("utf-8") except: msg = "[Can not display title because of an encoding error!]" print "%s\n title='%s' path='%s'\n" % (msg, title, docPath) title = msg content = item.getRendition(".xhtml.body") if content is None: content = "<p>[Not rendered!]</p>" contentElem = ElementTree.XML(content) firstPara = contentElem.find("p") summary = "No summary" if firstPara != None: summary = ElementTree.tostring(firstPara) name = item.name lastModifiedTime = self.iceContext.fs.getModifiedTime( self.rep.getAbsPath(name)) entryDate = datetime.fromtimestamp( lastModifiedTime).isoformat() + 'Z' srcUrl = "http://%s:%s%s" % (self.hostname, self.iceWebPort, docPath) entry = atom.Entry(title=atom.Title(text=title)) entry.id = atom.Id(text="urn:uid:%s" % id) entry.link = [atom.Link(href=srcUrl, rel="alternate")] entry.updated = atom.Updated(text=entryDate) entry.published = atom.Published(text=entryDate) entry.summary = atom.Summary(summary_type="html", text=unicode(summary, "utf-8")) entry.content = atom.Content(content_type="html", text=unicode(content, "utf-8")) return entry else: return None
def test_create_update_delete(self): if not conf.options.get_value('runlive') == 'true': return # Either load the recording or prepare to make a live request. conf.configure_cache(self.client, 'test_create_update_delete') blog_post = atom.Entry( title=atom.Title(text='test from python BloggerTest'), content=atom.Content(text='This is only a test.')) http_request = atom.http_core.HttpRequest() http_request.add_body_part(str(blog_post), 'application/atom+xml') def entry_from_string_wrapper(response): self.assertTrue(response.getheader('content-type') is not None) self.assertTrue(response.getheader('gdata-version') is not None) return atom.EntryFromString(response.read()) entry = self.client.request( 'POST', 'http://www.blogger.com/feeds/%s/posts/default' % (conf.options.get_value('blogid')), converter=entry_from_string_wrapper, http_request=http_request) self.assertEqual(entry.title.text, 'test from python BloggerTest') self.assertEqual(entry.content.text, 'This is only a test.') # Edit the test entry. edit_link = None for link in entry.link: # Find the edit link for this entry. if link.rel == 'edit': edit_link = link.href entry.title.text = 'Edited' http_request = atom.http_core.HttpRequest() http_request.add_body_part(str(entry), 'application/atom+xml') edited_entry = self.client.request('PUT', edit_link, converter=entry_from_string_wrapper, http_request=http_request) self.assertEqual(edited_entry.title.text, 'Edited') self.assertEqual(edited_entry.content.text, entry.content.text) # Delete the test entry from the blog. edit_link = None for link in edited_entry.link: if link.rel == 'edit': edit_link = link.href response = self.client.request('DELETE', edit_link) self.assertEqual(response.status, 200)
def test_create_update_delete(self): if not conf.settings.RUN_LIVE_TESTS: return # Either load the recording or prepare to make a live request. conf.configure_cache(self.client, 'test_create_update_delete') blog_post = atom.Entry( title=atom.Title(text=conf.settings.BloggerConfig.title), content=atom.Content(text=conf.settings.BloggerConfig.content)) http_request = atom.http_core.HttpRequest() http_request.add_body_part(str(blog_post), 'application/atom+xml') def entry_from_string_wrapper(response): return atom.EntryFromString(response.read()) entry = self.client.request( 'POST', 'http://www.blogger.com/feeds/%s/posts/default' % (conf.settings.BloggerConfig.blog_id), converter=entry_from_string_wrapper, http_request=http_request) self.assertEqual(entry.title.text, conf.settings.BloggerConfig.title) # TODO: uncomment once server bug is fixed #self.assertEqual(entry.content.text, conf.settings.BloggerConfig.content) # Edit the test entry. edit_link = None for link in entry.link: # Find the edit link for this entry. if link.rel == 'edit': edit_link = link.href entry.title.text = 'Edited' http_request = atom.http_core.HttpRequest() http_request.add_body_part(str(entry), 'application/atom+xml') edited_entry = self.client.request('PUT', edit_link, converter=entry_from_string_wrapper, http_request=http_request) self.assertEqual(edited_entry.title.text, 'Edited') # TODO: uncomment once server bug is fixed #self.assertEqual(edited_entry.content.text, entry.content.text) # Delete the test entry from the blog. edit_link = None for link in edited_entry.link: if link.rel == 'edit': edit_link = link.href response = self.client.request('DELETE', edit_link) self.assertEqual(response.status, 200)
def modifyBlogRedirectUrl(blog_id, proxy_url, client): """ Modifies the given blog settings to make the feed redirect to the given proxy. """ # The basic idea here is to PUT a new value to the Atom entry defined at # /feeds/blogid/settings/BLOG_FEED_REDIRECT_URL, which updates it. I'm not sure # why the code also needs to see the BLOG_FEED_REDIRECT_URL name in the id as well # as the POSTed URL... anyway, this works and it's just for demo purposes: data = atom.Entry( atom_id=atom.Id(text='tag:blogger.com,1999:blog-' + blog_id + '.settings.BLOG_FEED_REDIRECT_URL'), content=atom.Content(text=proxy_url) ) # The content of the setting is just the proxy URL logging.info("Data is: %s", data) uri = 'http://www.blogger.com/feeds/' + blog_id + '/settings/BLOG_FEED_REDIRECT_URL' client.blogger.Put(data, uri, extra_headers=None, url_params=None)
def testConvertToAndFromElementTree(self): # Use entry because FeedEntryParent doesn't have a tag or namespace. original = atom.Entry() copy = atom.FeedEntryParent() original.author.append(atom.Author(name=atom.Name(text='J Scud'))) self.assert_(original.author[0].name.text == 'J Scud') self.assert_(copy.author == []) original.id = atom.Id(text='test id') self.assert_(original.id.text == 'test id') self.assert_(copy.id is None) copy._HarvestElementTree(original._ToElementTree()) self.assert_(original.author[0].name.text == copy.author[0].name.text) self.assert_(original.id.text == copy.id.text)
def testConvertToAndFromString(self): feed = atom.Feed() feed.author.append(atom.Author(name=atom.Name(text='js'))) feed.title = atom.Title(text='my test source') feed.generator = atom.Generator(text='gen') feed.entry.append( atom.Entry( author=[atom.Author(name=atom.Name(text='entry author'))])) self.assert_(feed.author[0].name.text == 'js') self.assert_(feed.title.text == 'my test source') self.assert_(feed.generator.text == 'gen') self.assert_(feed.entry[0].author[0].name.text == 'entry author') new_feed = atom.FeedFromString(feed.ToString()) self.assert_(new_feed.author[0].name.text == 'js') self.assert_(new_feed.title.text == 'my test source') self.assert_(new_feed.generator.text == 'gen') self.assert_(new_feed.entry[0].author[0].name.text == 'entry author')
def test_feed(): e_link = atom.Element(name="link", href="http://example.org/2003/12/13/atom03") entry = atom.Entry(title="Atom-Powered Robots Run Amok", link=e_link, id="urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", updated="2003-12-13T18:30:02Z", summary="Some text.") e_author = atom.Element(name="author") e_author.set_preverse_attrs("name", "John Doe") e_link = atom.Element(name="link", href="http://example.org/") feed = atom.Feed(title="Example Feed", link=e_link, updated="2003-12-13T18:30:02Z", author=e_author, id="urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6") feed.append_children(entry) buf = str(feed) # assert buf == ( # "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" # " <feed xmlns=\"http://www.w3.org/2005/Atom\">\n" # " <title>Example Feed</title>\n" # " <link href=\"http://example.org/\"/>\n" # " <updated>2003-12-13T18:30:02Z</updated>\n" # " <author>\n" # " <name>John Doe</name>\n" # " </author>\n" # " <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>\n" # " <entry>\n" # " <title>Atom-Powered Robots Run Amok</title>\n" # " <link href=\"http://example.org/2003/12/13/atom03\"/>\n" # " <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>\n" # " <updated>2003-12-13T18:30:02Z</updated>\n" # " <summary>Some text.</summary>\n" # " </entry>\n" # "</feed>\n" # ) tree = etree.fromstring(buf)
def generate_feed(posts): author = atom.Author(name=settings['author'], email=settings['email']) entries = [] for post in posts[:5]: # Rewrite post path into the weird id form I used to use. id = settings['id_base'] + '/' + ( post.timestamp.strftime('%Y-%m-%d') + '/' + os.path.splitext(os.path.basename(post.path))[0]) timestamp = post.timestamp + datetime.timedelta(seconds=time.timezone) entries.append(atom.Entry(timestamp=timestamp, id=id, title=post.title, link=settings['link'] + post.path, content=post.content)) feed = atom.Feed(title=settings['title'], id=settings['id_base'], link=settings['link'], selflink=settings['link'] + 'atom.xml', author=author, entries=entries) return feed.to_xml()
def test_entry(): e_link = atom.Element(name="link", href="http://example.org/2003/12/13/atom03") entry = atom.Entry(title="Atom-Powered Robots Run Amok", link = e_link, id="urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", updated="2003-12-13T18:30:02Z", summary="Some text.") # assert str(entry) == ( # "<entry>\n" # " <summary>Some text.</summary>\n" # " <updated>2003-12-13T18:30:02Z</updated>\n" # " <link href=\"http://example.org/2003/12/13/atom03\"/>\n" # " <title>Atom-Powered Robots Run Amok</title>\n" # " <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>\n" # "</entry>\n" # ) tree = etree.fromstring(str(entry)) assert tree.attrib == {} assert tree.tag == "entry" assert not tree.text.strip() assert len(tree.getchildren()) == 5 e_summary = tree.xpath("/entry/summary")[0] assert e_summary.attrib == {} assert e_summary.tag == "summary" assert e_summary.text.strip() == "Some text." e_updated = tree.xpath("/entry/updated")[0] assert e_updated.attrib == {} assert e_updated.tag == "updated" assert e_updated.text.strip() == "2003-12-13T18:30:02Z" e_link = tree.xpath("/entry/link")[0] assert e_link.attrib == {'href' : "http://example.org/2003/12/13/atom03"} assert e_link.tag == "link" assert not e_link.text
def post(self): entry = atom.Entry(content=atom.Content(text=self.request.get('body'))) self.client.blogger.AddPost(entry, blog_id=self.request.get('id'))
def post(self): # Take care of incoming salmon # pull out oauth token, fire up OAuth client, identify # the particular post in question and its comment stream, # create an entry, and post a comment. blog_id = self.request.get('id') body = self.request.body.decode('utf-8') logging.info('Salmon body is:\n%s\n----', body) data = feedparser.parse(body) logging.info('Data parsed was:\n%s\n----', data) if data.bozo: logging.error('Bozo feed data. %s: %r', data.bozo_exception.__class__.__name__, data.bozo_exception) if (hasattr(data.bozo_exception, 'getLineNumber') and hasattr(data.bozo_exception, 'getMessage')): line = data.bozo_exception.getLineNumber() logging.error('Line %d: %s', line, data.bozo_exception.getMessage()) return self.response.set_status(400) logging.info('Found %d entries', len(data.entries)) for entry in data.entries: s = model.makeEntry(entry) referents = model.getTopicsOf(s) logging.info('Saw %d parent(s)', referents.count()) if referents.count() == 0: logging.info( 'No parent found for %s, returning error to client.', s.entry_id) self.response.set_status(400) self.response.out.write('Bad Salmon, no parent with id ' + unicode(s.in_reply_to) + ' found -- rejected.\n') return # Pull body & other info out of salmon # Create an Atom entry and post as a comment text = s.content # TODO: Fix Blogger so it accepts acct: URIs... sigh... name = re.sub("(..\@.+)", "...", s.author_name) author_uri = "http://example.org/profile/" + name #if author_uri.startswith("acct:"): # author_uri = author_uri.replace("acct:","http://") text = text + ' by <a href="' + author_uri + '">' + name + '</a>' entry = atom.Entry(content=atom.Content(text=text)) # Grab the entry ID from the in-reply-to element of the salmon p = re.compile('tag:blogger\.com,1999:blog-(\d+)\.post-(\d+)') m = p.match(s.in_reply_to) if not m: self.response.set_status(400) return blog_id = m.group(1) post_id = m.group(2) logging.info("About to post comment to blog %s, post %s", blog_id, post_id) # Grab auth info from DB (this is also an ACL check...) bp = BlogProxy.all().filter('blog_id =', blog_id).fetch(1)[0] origfeed = bp.feed_uri tokens = pickle.loads(bp.pickled_tokens) oauth_token = tokens["http://www.blogger.com/feeds/"] # TODO: Add some error checking, for Ghu's sake. # Let's see if override_token, at least, does what it says in this hall of # funhouse mirrors we call a GData client: self.client.blogger.override_token = oauth_token logging.info("Auth token = %s, override_token = %s", oauth_token, self.client.blogger.override_token) self.client.blogger.AddComment(entry, blog_id=blog_id, post_id=post_id) self.response.out.write("Salmon accepted, sent upstream to source!\n") self.response.set_status(200)