Source code for bpy.services.blogger

# Copyright (C) 2013-2016 by Yu-Jie Lin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

"""

Blogger service recognizes the following options in :ref:`brc.py`:

.. _blogger-brc:
.. code:: python

  service = 'blogger'
  service_options = {
    client_id: '<your client ID>',
    client_secret: '<your client secret>',
    'blog': <blog id>,
  }

You can use ``blogs`` command to quickly get the blog ID.


.. _Authorization:

Authorization
=============

You need to authorize *b.py* to access your Blogger account with your OAuth
`client ID`_. Simply using ``blogs`` command (see *Commands* section) to start
the authorization process:

.. code:: sh

  b.py blogs

Once you follow the prompted steps, there should be a b.dat_ created under the
current working directory, you should keep it safe.

.. _Client ID:

Client ID
=========

You will need to obtain a OAuth Client ID in order to use *b.py*.

1. Go to `Google Developers Console`_.
2. Create a new project.
3. Enable *Blogger API*.
4. Create a *OAuth client ID* credential with *Other* application type.
5. Download the credential JSON for *Client Secret*.
6. Add *Client ID* and *Client Secert* to your :ref:`brc.py` as shown here__.

.. _Google Developers Console:  https://console.developers.google.com/
__ blogger-brc_

.. _b.dat:

``b.dat``
=========

``b.dat`` is a credential file for Blogger service, it's read by *b.py* from
the current directory.

To create the file, please follow Authorization_.
"""

from __future__ import print_function

import os
import sys

import httplib2

from bpy.services.base import Service as BaseService

if sys.version_info.major == 2:
  from apiclient.discovery import build
  from oauth2client.client import OAuth2WebServerFlow
  from oauth2client.file import Storage as BaseStorage
  from oauth2client.tools import run_flow, argparser

  API_STORAGE = 'b.dat'

[docs] class Storage(BaseStorage): """Inherit the API Storage to suppress CredentialsFileSymbolicLinkError """ def __init__(self, filename): super(Storage, self).__init__(filename) self._filename_link_warned = False def _validate_file(self): if os.path.islink(self._filename) and not self._filename_link_warned: print('File: %s is a symbolic link.' % self._filename) self._filename_link_warned = True
[docs]class Service(BaseService): service_name = 'blogger' def __init__(self, *args, **kwargs): super(Service, self).__init__(*args, **kwargs) self.http = None self.service = None if 'client_id' not in self.options or 'client_secret' not in self.options: raise RuntimeError( 'You need to supply client ID and secret, see ' 'http://pythonhosted.org/b.py/apidoc/bpy.services.html#client-id' ) self.client_id = self.options['client_id'] self.client_secret = self.options['client_secret']
[docs] def auth(self): if sys.version_info.major != 2: msg = ('This command requires google-api-python-client, ' 'which only support Python 2') raise RuntimeError(msg) if self.http and self.service: return FLOW = OAuth2WebServerFlow( self.client_id, self.client_secret, 'https://www.googleapis.com/auth/blogger', auth_uri='https://accounts.google.com/o/oauth2/auth', token_uri='https://accounts.google.com/o/oauth2/token', ) storage = Storage(API_STORAGE) credentials = storage.get() if credentials is None or credentials.invalid: credentials = run_flow(FLOW, storage, argparser.parse_args([])) http = httplib2.Http() self.http = credentials.authorize(http) self.service = build("blogger", "v3", http=self.http)
[docs] def list_blogs(self): self.auth() blogs = self.service.blogs() req = blogs.listByUser(userId='self') resp = req.execute(http=self.http) print('%-20s: %s' % ('Blog ID', 'Blog name')) for blog in resp['items']: print('%-20s: %s' % (blog['id'], blog['name']))
[docs] def post(self): handler, post = self.make_handler_post() if 'blog' not in post: print('You need to specify which blog to post on ' 'in either brc.py or header of %s.' % handler.filename) sys.exit(1) self.auth() kind = post['kind'].replace('blogger#', '') title = post['title'] if kind == 'post': posts = self.service.posts() elif kind == 'page': posts = self.service.pages() else: raise ValueError('Unsupported kind: %s' % kind) data = { 'blogId': post['blog']['id'], 'body': post, } if 'id' in post: data['%sId' % kind] = post['id'] action = 'revert' if post['draft'] else 'publish' data[action] = True print('Updating a %s: %s' % (kind, title)) req = posts.update(**data) else: data['isDraft'] = post['draft'] print('Posting a new %s: %s' % (kind, title)) req = posts.insert(**data) resp = req.execute(http=self.http) resp['draft'] = resp['status'] == 'DRAFT' handler.merge_header(resp) handler.write()
[docs] def search(self, q): if self.options['blog'] is None: raise ValueError('no blog ID to search') self.auth() fields = 'items(labels,published,title,url)' posts = self.service.posts() req = posts.search(blogId=self.options['blog'], q=q, fields=fields) resp = req.execute(http=self.http) items = resp.get('items', []) print('Found %d posts on Blog %s' % (len(items), self.options['blog'])) print() for post in items: print(post['title']) labels = post.get('labels', []) if labels: print('Labels:', ', '.join(labels)) print('Published:', post['published']) print(post['url']) print()