views:

248

answers:

3

I'm trying to write a script that will automatically update some attachments on a website created and managed through Google Sites. This should be possible as Google released the Sites API in September and the Python GData API claims to support sites. However, the closest method I can find is called client.update, which allows me to update the metadata of an attachment, but not the content.

In the Java API updating an attachment is done by creating a new MediaFileSource and then calling entry.setMediaFileSource(source) followed by entry.updateMedia(). However, I can't find anything similar in the Python API. Am I dumb and just missing something, or is it really not possible to update a google sites attachment using the python API?

A: 

There is an upload_attachment method, that should work. You may also want to check out the [sample code][http://code.google.com/p/gdata-python-client/source/browse/trunk/samples/sites/sites_example.py] for Sites API, it uses that method.

livibetter
Unfortunately, while that works for uploading an attachment, it doesn't allow one to update an attachment, which is what I need to do. Calling `upload_attachment` with a duplicate filename returns the error: Server responded with: 409, Duplicate insert - node with name "test.txt" already exists - existing node id is 4770556649999999999
Pridkett
I think the only way is to use how Java library does: http://code.google.com/apis/sites/docs/1.0/developers_guide_protocol.html#UpdatingAnAttachmentCurrent Python library code use gdata protocol, which is undocumented. The workaround it the get the ClientLogin authorization from gdata client and make http request via PUT method on your own. Or delete the old file and upload new one, which is very awful.
livibetter
My impression is that the Java library also uses the GData protocol. So, from the sounds of it, it's not really possible to do in Python right now. I've thought about delete and re-add, but that's really awful and can mangle some links. Maybe I just need to wait a while...
Pridkett
+1  A: 

sites api has been updated to v1.1; this is probably a new addition

http://code.google.com/apis/sites/docs/1.0/developers_guide_python.html#UpdatingContent

manu1001
We have a winner, although their guide is slightly incorrect. Rather than using `entry.content.text = "YOUR NEW HTML"` you need to use `entry.content = atom.data.Content("YOUR NEW HTML")`, otherwise it just prepends the data. Your pointer was incredibly helpful in figuring this out.
Pridkett
+1  A: 

Ok, the API there is weird, and the documentation is not very clear. Here is what I have figured out. First time you upload an attachment, you do it through UploadAttachment method, but on the follow-up attempts, you need to call Update. Here's the code that does it:

class AttachmentUploader(object):
  """Uploads a given attachment to a given filecabinet in Google Sites."""

  def __init__(self, site, username, password):
    self.client = gdata.sites.client.SitesClient(
        source="uploaderScript", site=site)
    self.client.ssl = True
    try:
      self.client.ClientLogin(username, password, "some.key")
    except:
      traceback.print_exc()
      raise

  def FindAttachment(self, title):
    uri = "%s?kind=%s" % (self.client.MakeContentFeedUri(), "attachment")
    feed = self.client.GetContentFeed(uri=uri)
    for entry in feed.entry:
      if entry.title.text == title:
        return entry
    return None

  def FindCabinet(self, title):
    uri = "%s?kind=%s" % (self.client.MakeContentFeedUri(), "filecabinet")
    feed = self.client.GetContentFeed(uri=uri)
    for entry in feed.entry:
      if entry.title.text == title:
        return entry
    return None

  def Upload(self, cabinet_title, title, file_path, description):
    """Upload the given file as attachment."""
    ms = gdata.data.MediaSource(file_path=file_path, content_type="text/ascii")

    existing_attachment = self.FindAttachment(title)
    if existing_attachment is not None:
      existing_attachment.summary.text = description
      updated = self.client.Update(existing_attachment, media_source=ms)
      print "Updated: ", updated.GetAlternateLink().href
    else:
      cabinet = self.FindCabinet(cabinet_title)
      if cabinet is None:
        print "OUCH: cabinet %s does not exist" % cabinet_title
        return
      attachment = self.client.UploadAttachment(
          ms, cabinet, title=title, description=description)
      print "Uploaded: ", attachment.GetAlternateLink().href
Alex Gontmakher
Thanks for the detailed class to help out. The original problem was that the API didn't support updating attachments at the time. You still get points because this will be really helpful for folks looking for an implementation in the future.
Pridkett