#!/usr/bin/env python
# BloGTK Version 1.0
# Entry Posting/Editing Routines - post.py
# (C)2004 Jay Reding
# Code released under the terms of the BSD License. (See file LICENSE)
import pygtk
import gtk
import gtk.glade
import gobject
import xmlrpclib
import sys
import codecs
import string
import re
import xml
import proxy
# 0.5-1 - Python 2.3 doesn't like values named foo as arguments. Hence, I will
# be a smart-ass and replace 'None' with 'foo'
foo = 0
def getPostInfo(url, user, passwd, system, blogID, catID, title, body, publish, mainGlade, useUTF, extended, excerpt, keywords, trackbackURLS, breaks, commentsAllow, pingsAllow):
# 0.4 - Updated with correct appkey for BloGTK.
appkey = "542ACD141588E5FEA3970055CF5796008A9063"
if useUTF == "0":
# 0.9 - We're now going to convert our GTK unicode text to ISO8859-1, then we'll
# take this and make it valid for Python to handle.
body = unicode(body,"utf-8").encode("iso8859-15", "xmlcharrefreplace")
title = unicode(title,"utf-8").encode("iso8859-15", "xmlcharrefreplace")
newbody = ""
newtitle = ""
newexcerpt = ""
newext = ""
# 0.9 - This is a very slow way of appending strings... I should do this better, but I
# can't get the faster way to work...
for ch in body:
c = ord(ch)
if c > 0x7F:
newbody = newbody + ("&#x%X;" % (c))
continue
else:
newbody = newbody + (ch)
for ch in title:
c = ord(ch)
if c > 0x7F:
newtitle = newtitle + ("&#x%X;" % (c))
continue
else:
newtitle = newtitle + (ch)
for ch in excerpt:
c = ord(ch)
if c > 0x7F:
newexcerpt = newexcerpt + ("&#x%X;" % (c))
continue
else:
newexcerpt = newexcerpt + (ch)
for ch in extended:
c = ord(ch)
if c > 0x7F:
newext = newext + ("&#x%X;" % (c))
continue
else:
newext = newext + (ch)
body = newbody
title = newtitle
excerpt = newexcerpt
extended = newext
else:
pass
if system == "blogger":
bloggerPost(url, user, passwd, appkey, blogID, body, publish, mainGlade)
if system == "mt":
mtPost(url, user, passwd, blogID, catID, title, body, publish, mainGlade, excerpt, extended, pingsAllow, commentsAllow, breaks, keywords, trackbackURLS)
if system == "metaweblog":
metaweblogPost(url, user, passwd, blogID, title, body, publish, mainGlade, excerpt, extended, keywords)
def bloggerPost(url, user, passwd, appkey, blogID, body, publish, mainGlade):
rpcServer = proxy.get_xmlrpc_server(url)
if publish == 1:
pubBool = xmlrpclib.True
if publish == 0:
pubBool = xmlrpclib.False
post = rpcServer.blogger.newPost(appkey, blogID, user, passwd, body, pubBool)
confirmPost(post, mainGlade)
return post
def mtPost(url, user, passwd, blogID, catID, title, body, publish, mainGlade, excerpt, extended, pingsAllow, commentsAllow, breaks, keywords, trackbackURLS):
rpcServer = proxy.get_xmlrpc_server(url)
# Create the struct with the post's content.
content = {}
content['title'] = title
content['description'] = body
content['mt_text_more'] = extended
content['mt_excerpt'] = excerpt
content['mt_keywords'] = keywords
content['mt_allow_comments'] = int(commentsAllow)
content['mt_allow_pings'] = int(pingsAllow)
content['mt_convert_breaks'] = breaks
# 0.95 - We also need to create an array with our list of trackback URLS.
# Each URL should be separated by a comma and trailing space.
trackbackArray = []
for item in trackbackURLS.split(", "):
trackbackArray.append(item)
content['mt_tb_ping_urls'] = trackbackArray
# Create the struct with the category informtion, then pass that to a list.
catList = []
category = {}
category['categoryId'] = catID
category['isPrimary'] = xmlrpclib.True
catList.append(category)
# Send the XML-RPC call to make the post
post = rpcServer.metaWeblog.newPost(blogID, user, passwd, content, publish)
# Set the category for the post
catAssign = rpcServer.mt.setPostCategories(post, user, passwd, catList)
confirmPost(post, mainGlade)
return post
def metaweblogPost(url, user, passwd, blogID, title, body, publish, mainGlade, excerpt, extended, keywords):
rpcServer = xmlrpclib.Server(url)
if publish == 1:
pubBool = xmlrpclib.True
if publish == 0:
pubBool = xmlrpclib.False
# Create the struct with the post's content.
content = {}
content['title'] = title
content['description'] = body
content['mt_text_more'] = extended
content['mt_excerpt'] = excerpt
content['mt_keywords'] = keywords
# Send the XML-RPC call to make the post
post = rpcServer.metaWeblog.newPost(blogID, user, passwd, content, pubBool)
confirmPost(post, mainGlade)
return post
def confirmPost(post, mainGlade):
# 0.6 - Let's make sure the confirmation window is properly parented. Good parenting is
# important unless we want our confirmation window to become a pothead later in life...
mainWindow = mainGlade.get_widget('mainWindow')
# Pop up a dialog confirming the post.
postDialog = gtk.Dialog(title="Entry Posted", parent=mainWindow, flags=0)
button2 = gtk.Button(stock=gtk.STOCK_OK)
button2.connect_object("clicked", gtk.Widget.destroy, postDialog)
postDialog.action_area.pack_start(button2, gtk.TRUE, gtk.TRUE, 0)
button2.show()
postLabel = gtk.Label("Entry Posted. ID = " + post)
postDialog.vbox.pack_start(postLabel, gtk.TRUE, gtk.TRUE, 2)
postLabel.show()
postDialog.show()
# 0.6 - Attach the post ID# to the holder widget. This way, if the user hits
# the publish button again it will edit the post rather than create a new
# one.
postIDLabel = mainGlade.get_widget('postIDLabel')
postIDLabel.set_text(post)
# 0.6 - After posting, set the status bar to also confirm the post.
mainStatus = mainGlade.get_widget('mainStatus')
mainStatus.push(1, "Your entry was posted with Post ID# " + post)
return post
# 0.4 - BEGIN PREVIOUS ENTRY RECALL CODE FOR MOVABLE TYPE
def mt_grabPostList(mainGlade, url, user, passwd, system, blogID, model, treeView, retrievalNumber):
# 0.4 - This function retrieves a list of previous posts and displays it in the post recall
# window.
editButton = mainGlade.get_widget('editPostButton')
deleteButton = mainGlade.get_widget('delPostButton')
mainStatus = mainGlade.get_widget('mainStatus')
# 0.95 - Rather than use the old popdown menu, we're now using a TreeView instead. We also
# have a config item that lets us know how many entries to process...
rpcServer = proxy.get_xmlrpc_server(url, server=xmlrpclib.ServerProxy)
new = int(float(retrievalNumber))
try:
result = rpcServer.metaWeblog.getRecentPosts(blogID, user, passwd, new)
for item in result:
try:
treeIter=model.append(None)
model.set_value(treeIter,0,item["title"])
except:
pass
selection = treeView.get_selection()
selection.connect("changed", mt_fillView, selection, model, treeView, result, mainGlade)
editButton.connect("clicked", mt_sendPostToWindow, mainGlade, result, selection, url, user, passwd, rpcServer, model)
deleteButton.connect("clicked", mt_getPostID, mainGlade, result, selection, url, user, passwd, rpcServer, model)
except xmlrpclib.Error, v:
print "BloGTK could not read the response from the server. Try limiting the amount"
print "of retrieved entries or check to make sure your posts contain valid XML."
mainStatus.push(1, "BloGTK could not retrieve previous post listing.")
except xml.parsers.expat.ExpatError, error:
print "BloGTK could not read the response from the server. Try limiting the amount"
print "of retrieved entries or check to make sure your posts contain valid XML."
mainStatus.push(1, "BloGTK could not retrieve previous post listing.")
def mt_getPostID(foo, mainGlade, result, selection, url, user, passwd, rpcServer, model):
moof, iter = selection.get_selected()
title = model.get_value(iter,0)
postNum = ""
for item in result:
for k,v in item.items():
if item['title'] == title:
postNum = item['postid']
deletePost(foo, user, passwd, rpcServer, postNum, mainGlade, model)
def mt_fillView(foo, selection, model, treeView, result, mainGlade):
moof, iter = selection.get_selected()
textView = mainGlade.get_widget('postReview_View')
try:
title = model.get_value(iter,0)
for item in result:
for k,v in item.items():
if item['title'] == title:
text = item['description']
else:
pass
buffer = gtk.TextBuffer()
buffer.set_text(text)
textView.set_buffer(buffer)
except:
pass
def mt_sendPostToWindow(foo, mainGlade, result, selection, url, user, passwd, rpcServer, model):
# 0.4 - Let's grab the entry field we need to update from the Glade file.
bodyView = mainGlade.get_widget('bodyView')
titleEntry = mainGlade.get_widget('titleEntry')
postIDLabel = mainGlade.get_widget('postIDLabel')
extendedView = mainGlade.get_widget('extendedView')
excerptView = mainGlade.get_widget('excerptView')
keywordsEntry = mainGlade.get_widget('keywordEntry')
moof, iter = selection.get_selected()
try:
postTitle = model.get_value(iter,0)
except:
pass
for item in result:
for k,v in item.items():
if item['title'] == postTitle:
text = item['description']
postId = item['postid']
extended = item['mt_text_more']
excerpt = item['mt_excerpt']
try:
keywords = item['mt_keywords']
except:
pass
titleEntry.set_text(postTitle)
buffer = gtk.TextBuffer()
buffer.set_text(text)
bodyView.set_buffer(buffer)
# 0.95 - Now we need to add in our additional fields to their respective
# places.
buffer2 = gtk.TextBuffer()
buffer2.set_text(extended)
extendedView.set_buffer(buffer2)
buffer3 = gtk.TextBuffer()
buffer3.set_text(excerpt)
excerptView.set_buffer(buffer3)
try:
keywordsEntry.set_text(keywords)
except:
pass
postIDLabel.set_text(postId)
# 0.4 - Now we need to retrieve the list of categories that the post belongs
# to and set the primary category in the catCombo box.
catCombo = mainGlade.get_widget('catCombo')
cats = rpcServer.mt.getPostCategories(postId, user, passwd)
catName = ""
for item in cats:
for k,v in item.items():
if item['isPrimary'] == xmlrpclib.True:
catName = item['categoryName']
catCombo.entry.set_text(catName)
editWindow = mainGlade.get_widget('recallDialog')
editWindow.hide()
model.clear()
# 0.4 - BEGIN PREVIOUS ENTRY RECALL CODE FOR BLOGGER
def blogger_grabPostList(mainGlade, url, user, passwd, system, blogID, model, treeView, retrievalNumber):
# 0.4 - This function retrieves a list of previous posts and displays it in the post recall
# window.
editButton = mainGlade.get_widget('editPostButton')
deleteButton = mainGlade.get_widget('delPostButton')
new = int(float(retrievalNumber))
appkey = "542ACD141588E5FEA3970055CF5796008A9063"
rpcServer = proxy.get_xmlrpc_server(url)
try:
result = rpcServer.blogger.getRecentPosts(appkey, blogID, user, passwd, new)
for item in result:
try:
treeIter=model.append(None)
model.set_value(treeIter,0,item["postid"])
except:
pass
selection = treeView.get_selection()
selection.connect("changed", blogger_fillView, selection, model, treeView, result, mainGlade)
editButton.connect("clicked", blogger_sendPostToWindow, mainGlade, result, selection, url, user, passwd, rpcServer, model)
deleteButton.connect("clicked", blogger_getPostID, mainGlade, result, selection, url, user, passwd, rpcServer, model)
except xmlrpclib.Error, v:
print "An error " + xmlrpclib.Error + " , " + v |+" occurred while retrieving entries. Try retrieving a smaller number of entries."
except xml.parsers.expat.ExpatError, error:
print "BloGTK could not read the response from the server. Try limiting the amount"
print "of retrieved entries or check to make sure your posts contain valid XML"
def blogger_getPostID(foo, mainGlade, result, selection, url, user, passwd, rpcServer, model):
# 0.4 - This routine is necessary to make sure that the postsNum value is changed when the
# postsCombo value is changed.
moof, iter = selection.get_selected()
postNum = model.get_value(iter,0)
deletePost(foo, user, passwd, rpcServer, postNum, mainGlade, model)
def blogger_fillView(foo, selection, model, treeView, result, mainGlade):
moof, iter = selection.get_selected()
textView = mainGlade.get_widget('postReview_View')
try:
postID = model.get_value(iter,0)
for item in result:
for k,v in item.items():
if item['postid'] == postID:
text = item['content']
buffer = gtk.TextBuffer()
buffer.set_text(text)
textView.set_buffer(buffer)
except:
pass
def blogger_sendPostToWindow(foo, mainGlade, result, selection, url, user, passwd, rpcServer, model):
# 0.4 - Let's grab the entry field we need to update from the Glade file.
bodyView = mainGlade.get_widget('bodyView')
titleEntry = mainGlade.get_widget('titleEntry')
postIDLabel = mainGlade.get_widget('postIDLabel')
moof, iter = selection.get_selected()
try:
postId = model.get_value(iter,0)
except:
pass
for item in result:
for k,v in item.items():
if item['postid'] == postId:
text = item['content']
buffer = gtk.TextBuffer()
buffer.set_text(text)
bodyView.set_buffer(buffer)
postIDLabel.set_text(postId)
editWindow = mainGlade.get_widget('recallDialog')
editWindow.hide()
model.clear()
# 0.4 - BEGIN PREVIOUS ENTRY RECALL CODE FOR METAWEBLOG API
def mw_grabPostList(mainGlade, url, user, passwd, system, blogID, model, treeView, retrievalNumber):
# 0.4 - This function retrieves a list of previous posts and displays it in the post recall
# window.
editButton = mainGlade.get_widget('editPostButton')
deleteButton = mainGlade.get_widget('delPostButton')
# 0.95 - Rather than use the old popdown menu, we're now using a TreeView instead. We also
# have a config item that lets us know how many entries to process...
rpcServer = proxy.get_xmlrpc_server(url, server=xmlrpclib.ServerProxy)
new = int(float(retrievalNumber))
try:
result = rpcServer.metaWeblog.getRecentPosts(blogID, user, passwd, new)
for item in result:
try:
treeIter=model.append(None)
model.set_value(treeIter,0,item["title"])
except:
pass
selection = treeView.get_selection()
selection.connect("changed", mw_fillView, selection, model, treeView, result, mainGlade)
editButton.connect("clicked", mw_sendPostToWindow, mainGlade, result, selection, url, user, passwd, rpcServer, model)
deleteButton.connect("clicked", mw_getPostID, mainGlade, result, selection, url, user, passwd, rpcServer, model)
except xmlrpclib.Error, v:
print "An error " + xmlrpclib.Error + " , " + v |+" occurred while retrieving entries. Try retrieving a smaller number of entries."
except xml.parsers.expat.ExpatError, error:
print "BloGTK could not read the response from the server. Try limiting the amount"
print "of retrieved entries or check to make sure your posts contain valid XML"
def mw_getPostID(foo, mainGlade, result, selection, url, user, passwd, rpcServer, model):
moof, iter = selection.get_selected()
title = model.get_value(iter,0)
postNum = ""
for item in result:
for k,v in item.items():
if item['title'] == title:
postNum = item['postid']
deletePost(foo, user, passwd, rpcServer, postNum, mainGlade, model)
def mw_fillView(foo, selection, model, treeView, result, mainGlade):
moof, iter = selection.get_selected()
textView = mainGlade.get_widget('postReview_View')
try:
title = model.get_value(iter,0)
for item in result:
for k,v in item.items():
if item['title'] == title:
text = item['description']
buffer = gtk.TextBuffer()
buffer.set_text(text)
textView.set_buffer(buffer)
except:
pass
def mw_sendPostToWindow(foo, mainGlade, result, selection, url, user, passwd, rpcServer, model):
# 0.4 - Let's grab the entry field we need to update from the Glade file.
bodyView = mainGlade.get_widget('bodyView')
titleEntry = mainGlade.get_widget('titleEntry')
postIDLabel = mainGlade.get_widget('postIDLabel')
extendedView = mainGlade.get_widget('extendedView')
excerptView = mainGlade.get_widget('excerptView')
moof, iter = selection.get_selected()
try:
postTitle = model.get_value(iter,0)
except:
pass
for item in result:
for k,v in item.items():
if item['title'] == postTitle:
text = item['description']
postId = item['postid']
extended = item['mt_text_more']
excerpt = item['mt_excerpt']
titleEntry.set_text(postTitle)
buffer = gtk.TextBuffer()
buffer.set_text(text)
bodyView.set_buffer(buffer)
buffer.set_text(extended)
extendedView.set_buffer(buffer)
buffer.set_text(excerpt)
excerptView.set_buffer(buffer)
postIDLabel.set_text(postId)
editWindow = mainGlade.get_widget('recallDialog')
editWindow.hide()
model.clear()
# 0.4 - BEGIN COMMON DELETE POST CODE
def deletePost(foo, user, passwd, rpcServer, postNum, mainGlade, model):
appkey = "542ACD141588E5FEA3970055CF5796008A9063"
confirmDelete = mainGlade.get_widget('confirmDelete')
ok_deletePost = mainGlade.get_widget('ok_deletePost')
cancel_deletePost = mainGlade.get_widget('cancel_deletePost')
ok_deletePost.connect('clicked', doDeletePost, appkey, user, passwd, rpcServer, postNum, confirmDelete, mainGlade, model)
cancel_deletePost.connect('clicked', hideDeleteConf, confirmDelete)
confirmDelete.show()
def doDeletePost(foo, appkey, user, passwd, rpcServer, postNum, confirmDelete, mainGlade, model):
# 0.9-3 - If we delete a post that's currently being re-edited, we want to make sure
# we don't try to repost the entry under an invalid ID...
postIDLabel = mainGlade.get_widget('postIDLabel')
postID2 = postIDLabel.get_text()
if postID2 == postNum:
print "Repost ID = Deleted Post ID"
postIDLabel.set_text("New")
else:
pass
try:
postDelete = rpcServer.blogger.deletePost(appkey, postNum, user, passwd, xmlrpclib.True)
except:
pass
postsWindow = mainGlade.get_widget('recallDialog')
model.clear()
confirmDelete.hide()
postsWindow.hide()
def hideDeleteConf(foo, confirmDelete):
confirmDelete.hide()
# 0.4 - BEGIN REPOSTING CODE
def repost(url, user, passwd, system, blogID, catID, title, body, publish, postID, mainGlade, useUTF, extended, excerpt, keywords, trackbackURLS, breaks, commentsAllow, pingsAllow):
# 0.4 - Updated with correct appkey for BloGTK.
appkey = "542ACD141588E5FEA3970055CF5796008A9063"
if useUTF == "0":
# 0.9 - We're now going to convert our GTK unicode text to ISO8859-1, then we'll
# take this and make it valid for Python to handle.
body = unicode(body,"utf-8").encode("iso8859-15", "xmlcharrefreplace")
title = unicode(title,"utf-8").encode("iso8859-15", "xmlcharrefreplace")
newbody = ""
newtitle = ""
newexcerpt = ""
newext = ""
# 0.9 - This is a very slow way of appending strings... I should do this better, but I
# can't get the faster way to work...
for ch in body:
c = ord(ch)
if c > 0x7F:
newbody = newbody + ("&#x%X;" % (c))
continue
else:
newbody = newbody + (ch);
for ch in title:
c = ord(ch)
if c > 0x7F:
newtitle = newtitle + ("&#x%X;" % (c))
continue
else:
newtitle = newtitle + (ch);
for ch in excerpt:
c = ord(ch)
if c > 0x7F:
newexcerpt = newexcerpt + ("&#x%X;" % (c))
continue
else:
newexcerpt = newexcerpt + (ch)
for ch in extended:
c = ord(ch)
if c > 0x7F:
newext = newext + ("&#x%X;" % (c))
continue
else:
newext = newext + (ch)
body = newbody
title = newtitle
excerpt = newexcerpt
extended = newext
else:
pass
if system == "blogger":
blogger_Repost(url, user, passwd, appkey, blogID, body, publish, postID, mainGlade)
if system == "mt":
mt_Repost(url, user, passwd, blogID, catID, title, body, publish, postID, mainGlade, extended, excerpt, keywords, commentsAllow, pingsAllow, breaks)
if system == "metaweblog":
metaweblog_Repost(url, user, passwd, blogID, title, body, publish, postID, mainGlade, extended, excerpt)
def blogger_Repost(url, user, passwd, appkey, blogID, body, publish, postID, mainGlade):
rpcServer = proxy.get_xmlrpc_server(url)
if publish == 1:
pubBool = xmlrpclib.True
if publish == 0:
pubBool = xmlrpclib.False
try:
repost = rpcServer.blogger.editPost(appkey, postID, user, passwd, body, pubBool)
except:
print "An error occured while editing this entry. Please try again."
confirmRepost(repost, mainGlade)
return repost
def mt_Repost(url, user, passwd, blogID, catID, title, body, publish, postID, mainGlade, extended, excerpt, keywords, commentsAllow, pingsAllow, breaks):
rpcServer = proxy.get_xmlrpc_server(url)
# Create the struct with the post's content.
content = {}
content['title'] = title
content['description'] = body
content['mt_excerpt'] = excerpt
content['mt_text_more'] = extended
content['mt_keywords'] = keywords
content['mt_allow_comments'] = int(commentsAllow)
content['mt_allow_pings'] = int(pingsAllow)
content['mt_convert_breaks'] = breaks
# Create the struct with the category informtion, then pass that to a list.
catList = []
category = {}
category['categoryId'] = catID
category['isPrimary'] = xmlrpclib.True
catList.append(category)
# Send the XML-RPC call to repost the entry.
try:
repost = rpcServer.metaWeblog.editPost(postID, user, passwd, content, publish)
except:
print "An error occurred while editing this post. Please try again."
# Set the category for the post
catAssign = rpcServer.mt.setPostCategories(postID, user, passwd, catList)
confirmRepost(repost, mainGlade)
return repost
def metaweblog_Repost(url, user, passwd, blogID, title, body, publish, postID, mainGlade, extended, excerpt):
rpcServer = proxy.get_xmlrpc_server(url)
# Create the struct with the post's content.
content = {}
content['title'] = title
content['description'] = body
content['mt_excerpt'] = excerpt
content['mt_keywords'] = keywords
# Send the XML-RPC call to repost the entry
try:
post = rpcServer.metaWeblog.editPost(postID, user, passwd, content, publish)
except:
print "An error occurred while editing this post. Please try again."
confirmRepost(repost, mainGlade)
return repost
def confirmRepost(repost, mainGlade):
# 0.6 - Let's make sure the confirmation window is properly parented. Good parenting is
# important unless we want our confirmation window to become a pothead later in life...
mainWindow = mainGlade.get_widget('mainWindow')
# Pop up a dialog confirming the post.
postDialog = gtk.Dialog(title="Entry Updated", parent=mainWindow, flags=0)
button2 = gtk.Button(stock=gtk.STOCK_OK)
button2.connect_object("clicked", gtk.Widget.destroy, postDialog)
postDialog.action_area.pack_start(button2, gtk.TRUE, gtk.TRUE, 0)
button2.show()
postLabel = gtk.Label("Your Entry Has Been Successfully Updated")
postDialog.vbox.pack_start(postLabel, gtk.TRUE, gtk.TRUE, 2)
postLabel.show()
postDialog.show()
# 0.6 - After posting, set the status bar to also confirm the post.
mainStatus = mainGlade.get_widget('mainStatus')
mainStatus.push(1, "Entry was successfully updated.")
return repost
|