PageRenderTime 151ms CodeModel.GetById 40ms app.highlight 16ms RepoModel.GetById 63ms app.codeStats 1ms

/src/googlecl/blogger/service.py

http://googlecl.googlecode.com/
Python | 214 lines | 134 code | 23 blank | 57 comment | 43 complexity | ea2ed7944e43d18148835ede4253957f MD5 | raw file
  1# Copyright (C) 2010 Google Inc.
  2#
  3# Licensed under the Apache License, Version 2.0 (the "License");
  4# you may not use this file except in compliance with the License.
  5# You may obtain a copy of the License at
  6#
  7#      http://www.apache.org/licenses/LICENSE-2.0
  8#
  9# Unless required by applicable law or agreed to in writing, software
 10# distributed under the License is distributed on an "AS IS" BASIS,
 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12# See the License for the specific language governing permissions and
 13# limitations under the License.
 14
 15
 16"""Service details and instances for the Blogger service."""
 17
 18
 19from __future__ import with_statement
 20
 21__author__ = 'tom.h.miller@gmail.com (Tom Miller)'
 22import atom
 23import gdata
 24import gdata.blogger
 25import gdata.blogger.service
 26import logging
 27import os
 28from googlecl import safe_encode
 29import googlecl.base
 30import googlecl.service
 31from googlecl.blogger import SECTION_HEADER
 32
 33
 34LOG = logging.getLogger(googlecl.blogger.LOGGER_NAME)
 35
 36
 37class BloggerServiceCL(gdata.blogger.service.BloggerService,
 38                       googlecl.service.BaseServiceCL):
 39
 40  """Command-line-friendly service for the Blogger API.
 41
 42  Some of this is based off gdata/samples/blogger/BloggerExampleV1.py
 43
 44  """
 45
 46  def __init__(self, config):
 47    """Constructor."""
 48    gdata.blogger.service.BloggerService.__init__(self, account_type='GOOGLE')
 49    googlecl.service.BaseServiceCL.__init__(self, SECTION_HEADER, config)
 50
 51  def _upload_content(self, post_title, content, blog_id=None, is_draft=False):
 52    """Uploads content.
 53
 54    Keyword arguments:
 55      blog_title: Title of the blog to post to.
 56      title: Title to give the post.
 57      content: String to get posted. This may be contents from a file, but NOT
 58               the path itself!
 59      is_draft: If this content is a draft post or not. (Default False)
 60
 61    Returns:
 62      Entry of post. (Returns same results as self.AddPost())
 63    """
 64    entry = gdata.blogger.BlogPostEntry()
 65    entry.title = atom.Title(title_type='xhtml', text=post_title)
 66    entry.content = atom.Content(content_type='html', text=content)
 67    if is_draft:
 68      control = atom.Control()
 69      control.draft = atom.Draft(text='yes')
 70      entry.control = control
 71    return self.AddPost(entry, blog_id)
 72
 73  def _get_blog_id(self, blog_title=None, user_id='default'):
 74    """Return the blog ID of the blog that matches blog_title.
 75
 76    Keyword arguments:
 77      blog_title: Name or title of the blog.
 78      user_id: Profile ID of blog's owner as seen in the profile view URL.
 79              Default 'default' for the authenticated user.
 80
 81    Returns:
 82      Blog ID (blog_entry.GetSelfLink().href.split('/')[-1]) if a blog is
 83      found matching the user and blog_title. None otherwise.
 84    """
 85    blog_entry = self.GetSingleEntry('/feeds/' + user_id + '/blogs', blog_title)
 86    if blog_entry:
 87      return blog_entry.GetSelfLink().href.split('/')[-1]
 88    else:
 89      if blog_title is not None:
 90        LOG.error('Did not find a blog with title matching %s', blog_title)
 91      else:
 92        LOG.error('No blogs found!')
 93      return None
 94
 95  def is_token_valid(self, test_uri='/feeds/default/blogs'):
 96    """Check that the token being used is valid."""
 97    return googlecl.service.BaseServiceCL.IsTokenValid(self, test_uri)
 98
 99  IsTokenValid = is_token_valid
100
101  def get_posts(self, blog_title=None, post_titles=None, user_id='default'):
102    """Get entries for posts that match a title.
103
104    Keyword arguments:
105      blog_title: Name or title of the blog the post is in. (Default None)
106      post_titles: string or list Titles that the posts should have.
107                   Default None, for all posts
108      user_id: Profile ID of blog's owner as seen in the profile view URL.
109              (Default 'default' for authenticated user)
110
111    Returns:
112      List of posts that match parameters, or [] if none do.
113    """
114    blog_id = self._get_blog_id(blog_title, user_id)
115    if blog_id:
116      uri = '/feeds/' + blog_id + '/posts/default'
117      return self.GetEntries(uri, post_titles)
118    else:
119      return []
120
121  GetPosts = get_posts
122
123  def label_posts(self, post_entries, tags):
124    """Add or remove labels on a list of posts.
125
126    Keyword arguments:
127      post_entries: List of post entry objects.
128      tags: String representation of tags in a comma separated list.
129            For how tags are generated from the string,
130            see googlecl.base.generate_tag_sets().
131    """
132    scheme = 'http://www.blogger.com/atom/ns#'
133    remove_set, add_set, replace_tags = googlecl.base.generate_tag_sets(tags)
134    successes = []
135    for post in post_entries:
136      # No point removing tags if we're replacing all of them.
137      if remove_set and not replace_tags:
138        # Keep categories if they meet one of two criteria:
139        # 1) Are of a different scheme than the one we're looking at, or
140        # 2) Are of the same scheme, but the term is in the 'remove' set
141        post.category = [c for c in post.category \
142                          if c.scheme != scheme or \
143                          (c.scheme == scheme and c.term not in remove_set)]
144
145      if replace_tags:
146        # Remove categories that match the scheme we are updating.
147        post.category = [c for c in post.category if c.scheme != scheme]
148      if add_set:
149        new_tags = [atom.Category(term=tag, scheme=scheme) for tag in add_set]
150        post.category.extend(new_tags)
151      updated_post = self.UpdatePost(post)
152      if updated_post:
153        successes.append(updated_post)
154    return successes
155
156  LabelPosts = label_posts
157
158  def upload_posts(self, content_list, blog_title=None, post_title=None,
159                   is_draft=False):
160    """Uploads posts.
161
162    Args:
163      content_list: List of filenames or content to upload.
164      blog_title: Name of the blog to upload to.
165      post_title: Name to give the post(s).
166      is_draft: Set True to upload as private draft(s), False to make upload(s)
167          public.
168
169    Returns:
170      List of entries of successful posts.
171    """
172    max_size = 500000
173    entry_list = []
174    blog_id = self._get_blog_id(blog_title)
175    if not blog_id:
176      return []
177    for content_string in content_list:
178      if os.path.exists(content_string):
179        with open(content_string, 'r') as content_file:
180          content = content_file.read(max_size)
181          if content_file.read(1):
182            LOG.warning('Only read first %s bytes of file %s' %
183                        (max_size, content_string))
184        if not post_title:
185          title = os.path.basename(content_string).split('.')[0]
186      else:
187        if not post_title:
188          title = 'New post'
189        content = content_string
190      try:
191        entry = self._upload_content(post_title or title,
192                                     content,
193                                     blog_id=blog_id,
194                                     is_draft=is_draft)
195      except self.request_error, err:
196        LOG.error(safe_encode('Failed to post: ' + unicode(err)))
197      else:
198        entry_list.append(entry)
199        if entry.control and entry.control.draft.text == 'yes':
200          html_link = _build_draft_html(entry)
201        else:
202          html_link = entry.GetHtmlLink().href
203        LOG.info('Post created: %s', html_link)
204    return entry_list
205
206  UploadPosts = upload_posts
207
208
209SERVICE_CLASS = BloggerServiceCL
210
211
212def _build_draft_html(entry):
213  template = 'http://www.blogger.com/post-edit.g?blogID=%s&postID=%s'
214  return template % (entry.GetBlogId(), entry.GetPostId())