PageRenderTime 31ms CodeModel.GetById 9ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/gdata/sites/client.py

http://radioappz.googlecode.com/
Python | 461 lines | 400 code | 14 blank | 47 comment | 0 complexity | e0e1646759c4463ffb7db099af0cf6f6 MD5 | raw file
  1#!/usr/bin/python
  2#
  3# Copyright 2009 Google Inc. All Rights Reserved.
  4#
  5# Licensed under the Apache License, Version 2.0 (the "License");
  6# you may not use this file except in compliance with the License.
  7# You may obtain a copy of the License at
  8#
  9#      http://www.apache.org/licenses/LICENSE-2.0
 10#
 11# Unless required by applicable law or agreed to in writing, software
 12# distributed under the License is distributed on an "AS IS" BASIS,
 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14# See the License for the specific language governing permissions and
 15# limitations under the License.
 16
 17"""SitesClient extends gdata.client.GDClient to streamline Sites API calls."""
 18
 19
 20__author__ = 'e.bidelman (Eric Bidelman)'
 21
 22import atom.data
 23import gdata.client
 24import gdata.sites.data
 25import gdata.gauth
 26
 27
 28# Feed URI templates
 29CONTENT_FEED_TEMPLATE = '/feeds/content/%s/%s/'
 30REVISION_FEED_TEMPLATE = '/feeds/revision/%s/%s/'
 31ACTIVITY_FEED_TEMPLATE = '/feeds/activity/%s/%s/'
 32SITE_FEED_TEMPLATE = '/feeds/site/%s/'
 33ACL_FEED_TEMPLATE = '/feeds/acl/site/%s/%s/'
 34
 35
 36class SitesClient(gdata.client.GDClient):
 37
 38  """Client extension for the Google Sites API service."""
 39
 40  host = 'sites.google.com'  # default server for the API
 41  domain = 'site'  # default site domain name
 42  api_version = '1.1'  # default major version for the service.
 43  auth_service = 'jotspot'
 44  auth_scopes = gdata.gauth.AUTH_SCOPES['jotspot']
 45
 46  def __init__(self, site=None, domain=None, auth_token=None, **kwargs):
 47    """Constructs a new client for the Sites API.
 48
 49    Args:
 50      site: string (optional) Name (webspace) of the Google Site
 51      domain: string (optional) Domain of the (Google Apps hosted) Site.
 52          If no domain is given, the Site is assumed to be a consumer Google
 53          Site, in which case the value 'site' is used.
 54      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
 55          OAuthToken which authorizes this client to edit the user's data.
 56      kwargs: The other parameters to pass to gdata.client.GDClient
 57          constructor.
 58    """
 59    gdata.client.GDClient.__init__(self, auth_token=auth_token, **kwargs)
 60    self.site = site
 61    if domain is not None:
 62      self.domain = domain
 63
 64  def __make_kind_category(self, label):
 65    if label is None:
 66      return None
 67    return atom.data.Category(
 68        scheme=gdata.sites.data.SITES_KIND_SCHEME,
 69        term='%s#%s' % (gdata.sites.data.SITES_NAMESPACE, label), label=label)
 70
 71  __MakeKindCategory = __make_kind_category
 72
 73  def __upload(self, entry, media_source, auth_token=None, **kwargs):
 74    """Uploads an attachment file to the Sites API.
 75
 76    Args:
 77      entry: gdata.sites.data.ContentEntry The Atom XML to include.
 78      media_source: gdata.data.MediaSource The file payload to be uploaded.
 79      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
 80          OAuthToken which authorizes this client to edit the user's data.
 81      kwargs: Other parameters to pass to gdata.client.post().
 82
 83    Returns:
 84      The created entry.
 85    """
 86    uri = self.make_content_feed_uri()
 87    return self.post(entry, uri, media_source=media_source,
 88                     auth_token=auth_token, **kwargs)
 89
 90  def _get_file_content(self, uri):
 91    """Fetches the file content from the specified URI.
 92
 93    Args:
 94      uri: string The full URL to fetch the file contents from.
 95
 96    Returns:
 97      The binary file content.
 98
 99    Raises:
100      gdata.client.RequestError: on error response from server.
101    """
102    server_response = self.request('GET', uri)
103    if server_response.status != 200:
104      raise  gdata.client.RequestError, {'status': server_response.status,
105                                         'reason': server_response.reason,
106                                         'body': server_response.read()}
107    return server_response.read()
108
109  _GetFileContent = _get_file_content
110
111  def make_content_feed_uri(self):
112    return CONTENT_FEED_TEMPLATE % (self.domain, self.site)
113
114  MakeContentFeedUri = make_content_feed_uri
115
116  def make_revision_feed_uri(self):
117    return REVISION_FEED_TEMPLATE % (self.domain, self.site)
118
119  MakeRevisionFeedUri = make_revision_feed_uri
120
121  def make_activity_feed_uri(self):
122    return ACTIVITY_FEED_TEMPLATE % (self.domain, self.site)
123
124  MakeActivityFeedUri = make_activity_feed_uri
125
126  def make_site_feed_uri(self, site_name=None):
127    if site_name is not None:
128      return (SITE_FEED_TEMPLATE % self.domain) + site_name
129    else:
130      return SITE_FEED_TEMPLATE % self.domain
131
132  MakeSiteFeedUri = make_site_feed_uri
133
134  def make_acl_feed_uri(self):
135    return ACL_FEED_TEMPLATE % (self.domain, self.site)
136
137  MakeAclFeedUri = make_acl_feed_uri
138
139  def get_content_feed(self, uri=None, auth_token=None, **kwargs):
140    """Retrieves the content feed containing the current state of site.
141
142    Args:
143      uri: string (optional) A full URI to query the Content feed with.
144      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
145          OAuthToken which authorizes this client to edit the user's data.
146      kwargs: Other parameters to pass to self.get_feed().
147
148    Returns:
149      gdata.sites.data.ContentFeed
150    """
151    if uri is None:
152      uri = self.make_content_feed_uri()
153    return self.get_feed(uri, desired_class=gdata.sites.data.ContentFeed,
154                         auth_token=auth_token, **kwargs)
155
156  GetContentFeed = get_content_feed
157
158  def get_revision_feed(self, entry_or_uri_or_id, auth_token=None, **kwargs):
159    """Retrieves the revision feed containing the revision history for a node.
160
161    Args:
162      entry_or_uri_or_id: string or gdata.sites.data.ContentEntry A full URI,
163          content entry node ID, or a content entry object of the entry to
164          retrieve revision information for.
165      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
166          OAuthToken which authorizes this client to edit the user's data.
167      kwargs: Other parameters to pass to self.get_feed().
168
169    Returns:
170      gdata.sites.data.RevisionFeed
171    """
172    uri = self.make_revision_feed_uri()
173    if isinstance(entry_or_uri_or_id, gdata.sites.data.ContentEntry):
174      uri = entry_or_uri_or_id.FindRevisionLink()
175    elif entry_or_uri_or_id.find('/') == -1:
176      uri += entry_or_uri_or_id
177    else:
178      uri = entry_or_uri_or_id
179    return self.get_feed(uri, desired_class=gdata.sites.data.RevisionFeed,
180                         auth_token=auth_token, **kwargs)
181
182  GetRevisionFeed = get_revision_feed
183
184  def get_activity_feed(self, uri=None, auth_token=None, **kwargs):
185    """Retrieves the activity feed containing recent Site activity.
186
187    Args:
188      uri: string (optional) A full URI to query the Activity feed.
189      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
190          OAuthToken which authorizes this client to edit the user's data.
191      kwargs: Other parameters to pass to self.get_feed().
192
193    Returns:
194      gdata.sites.data.ActivityFeed
195    """
196    if uri is None:
197      uri = self.make_activity_feed_uri()
198    return self.get_feed(uri, desired_class=gdata.sites.data.ActivityFeed,
199                         auth_token=auth_token, **kwargs)
200
201  GetActivityFeed = get_activity_feed
202
203  def get_site_feed(self, uri=None, auth_token=None, **kwargs):
204    """Retrieves the site feed containing a list of sites a user has access to.
205
206    Args:
207      uri: string (optional) A full URI to query the site feed.
208      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
209          OAuthToken which authorizes this client to edit the user's data.
210      kwargs: Other parameters to pass to self.get_feed().
211
212    Returns:
213      gdata.sites.data.SiteFeed
214    """
215    if uri is None:
216      uri = self.make_site_feed_uri()
217    return self.get_feed(uri, desired_class=gdata.sites.data.SiteFeed,
218                         auth_token=auth_token, **kwargs)
219
220  GetSiteFeed = get_site_feed
221
222  def get_acl_feed(self, uri=None, auth_token=None, **kwargs):
223    """Retrieves the acl feed containing a site's sharing permissions.
224
225    Args:
226      uri: string (optional) A full URI to query the acl feed.
227      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
228          OAuthToken which authorizes this client to edit the user's data.
229      kwargs: Other parameters to pass to self.get_feed().
230
231    Returns:
232      gdata.sites.data.AclFeed
233    """
234    if uri is None:
235      uri = self.make_acl_feed_uri()
236    return self.get_feed(uri, desired_class=gdata.sites.data.AclFeed,
237                         auth_token=auth_token, **kwargs)
238
239  GetAclFeed = get_acl_feed
240
241  def create_site(self, title, description=None, source_site=None,
242                  theme=None, uri=None, auth_token=None, **kwargs):
243    """Creates a new Google Site.
244
245    Note: This feature is only available to Google Apps domains.
246
247    Args:
248      title: string Title for the site.
249      description: string (optional) A description/summary for the site.
250      source_site: string (optional) The site feed URI of the site to copy.
251          This parameter should only be specified when copying a site.
252      theme: string (optional) The name of the theme to create the site with.
253      uri: string (optional) A full site feed URI to override where the site
254          is created/copied. By default, the site will be created under
255          the currently set domain (e.g. self.domain).
256      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
257          OAuthToken which authorizes this client to edit the user's data.
258      kwargs: Other parameters to pass to gdata.client.post().
259
260    Returns:
261      gdata.sites.data.SiteEntry of the created site.
262    """
263    new_entry = gdata.sites.data.SiteEntry(title=atom.data.Title(text=title))
264
265    if description is not None:
266      new_entry.summary = gdata.sites.data.Summary(text=description)
267
268    # Add the source link if we're making a copy of a site.
269    if source_site is not None:
270      source_link = atom.data.Link(rel=gdata.sites.data.SITES_SOURCE_LINK_REL,
271                                   type='application/atom+xml',
272                                   href=source_site)
273      new_entry.link.append(source_link)
274
275    if theme is not None:
276      new_entry.theme = gdata.sites.data.Theme(text=theme)
277
278    if uri is None:
279      uri = self.make_site_feed_uri()
280
281    return self.post(new_entry, uri, auth_token=auth_token, **kwargs)
282
283  CreateSite = create_site
284
285  def create_page(self, kind, title, html='', page_name=None, parent=None,
286                  auth_token=None, **kwargs):
287    """Creates a new page (specified by kind) on a Google Site.
288
289    Args:
290      kind: string The type of page/item to create. For example, webpage,
291          listpage, comment, announcementspage, filecabinet, etc. The full list
292          of supported kinds can be found in gdata.sites.gdata.SUPPORT_KINDS.
293      title: string Title for the page.
294      html: string (optional) XHTML for the page's content body.
295      page_name: string (optional) The URL page name to set. If not set, the
296          title will be normalized and used as the page's URL path.
297      parent: string or gdata.sites.data.ContentEntry (optional) The parent
298          entry or parent link url to create the page under.
299      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
300          OAuthToken which authorizes this client to edit the user's data.
301      kwargs: Other parameters to pass to gdata.client.post().
302
303    Returns:
304      gdata.sites.data.ContentEntry of the created page.
305    """
306    new_entry = gdata.sites.data.ContentEntry(
307        title=atom.data.Title(text=title), kind=kind,
308        content=gdata.sites.data.Content(text=html))
309
310    if page_name is not None:
311      new_entry.page_name = gdata.sites.data.PageName(text=page_name)
312
313    # Add parent link to entry if it should be uploaded as a subpage.
314    if isinstance(parent, gdata.sites.data.ContentEntry):
315      parent_link = atom.data.Link(rel=gdata.sites.data.SITES_PARENT_LINK_REL,
316                                   type='application/atom+xml',
317                                   href=parent.GetSelfLink().href)
318      new_entry.link.append(parent_link)
319    elif parent is not None:
320      parent_link = atom.data.Link(rel=gdata.sites.data.SITES_PARENT_LINK_REL,
321                                   type='application/atom+xml',
322                                   href=parent)
323      new_entry.link.append(parent_link)
324
325    return self.post(new_entry, self.make_content_feed_uri(),
326                     auth_token=auth_token, **kwargs)
327
328  CreatePage = create_page
329
330  def create_webattachment(self, src, content_type, title, parent,
331                           description=None, auth_token=None, **kwargs):
332    """Creates a new webattachment within a filecabinet.
333
334    Args:
335      src: string The url of the web attachment.
336      content_type: string The MIME type of the web attachment.
337      title: string The title to name the web attachment.
338      parent: string or gdata.sites.data.ContentEntry (optional) The
339          parent entry or url of the filecabinet to create the attachment under.
340      description: string (optional) A summary/description for the attachment.
341      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
342          OAuthToken which authorizes this client to edit the user's data.
343      kwargs: Other parameters to pass to gdata.client.post().
344
345    Returns:
346      gdata.sites.data.ContentEntry of the created page.
347    """
348    new_entry = gdata.sites.data.ContentEntry(
349        title=atom.data.Title(text=title), kind='webattachment',
350        content=gdata.sites.data.Content(src=src, type=content_type))
351
352    if isinstance(parent, gdata.sites.data.ContentEntry):
353      link = atom.data.Link(rel=gdata.sites.data.SITES_PARENT_LINK_REL,
354                            type='application/atom+xml',
355                            href=parent.GetSelfLink().href)
356    elif parent is not None:
357      link = atom.data.Link(rel=gdata.sites.data.SITES_PARENT_LINK_REL,
358                            type='application/atom+xml', href=parent)
359
360    new_entry.link.append(link)
361
362    # Add file decription if it was specified
363    if description is not None:
364      new_entry.summary = gdata.sites.data.Summary(type='text',
365                                                   text=description)
366
367    return self.post(new_entry, self.make_content_feed_uri(),
368                     auth_token=auth_token, **kwargs)
369
370  CreateWebAttachment = create_webattachment
371
372  def upload_attachment(self, file_handle, parent, content_type=None,
373                        title=None, description=None, folder_name=None,
374                        auth_token=None, **kwargs):
375    """Uploads an attachment to a parent page.
376
377    Args:
378      file_handle: MediaSource or string A gdata.data.MediaSource object
379          containing the file to be uploaded or the full path name to the
380          file on disk.
381      parent: gdata.sites.data.ContentEntry or string The parent page to
382          upload the file to or the full URI of the entry's self link.
383      content_type: string (optional) The MIME type of the file
384          (e.g 'application/pdf'). This should be provided if file is not a
385          MediaSource object.
386      title: string (optional) The title to name the attachment. If not
387          included, the filepath or media source's filename is used.
388      description: string (optional) A summary/description for the attachment.
389      folder_name: string (optional) The name of an existing folder to upload
390          the attachment to. This only applies when the parent parameter points
391          to a filecabinet entry.
392      auth_token: (optional) gdata.gauth.ClientLoginToken, AuthSubToken, or
393          OAuthToken which authorizes this client to edit the user's data.
394      kwargs: Other parameters to pass to self.__upload().
395
396    Returns:
397      A gdata.sites.data.ContentEntry containing information about the created
398      attachment.
399    """
400    if isinstance(parent, gdata.sites.data.ContentEntry):
401      link = atom.data.Link(rel=gdata.sites.data.SITES_PARENT_LINK_REL,
402                            type='application/atom+xml',
403                            href=parent.GetSelfLink().href)
404    else:
405      link = atom.data.Link(rel=gdata.sites.data.SITES_PARENT_LINK_REL,
406                            type='application/atom+xml',
407                            href=parent)
408
409    if not isinstance(file_handle, gdata.data.MediaSource):
410      ms = gdata.data.MediaSource(file_path=file_handle,
411                                  content_type=content_type)
412    else:
413      ms = file_handle
414
415    # If no title specified, use the file name
416    if title is None:
417      title = ms.file_name
418
419    new_entry = gdata.sites.data.ContentEntry(kind='attachment')
420    new_entry.title = atom.data.Title(text=title)
421    new_entry.link.append(link)
422
423    # Add file decription if it was specified
424    if description is not None:
425      new_entry.summary = gdata.sites.data.Summary(type='text',
426                                                   text=description)
427
428    # Upload the attachment to a filecabinet folder?
429    if parent.Kind() == 'filecabinet' and folder_name is not None:
430      folder_category = atom.data.Category(
431          scheme=gdata.sites.data.FOLDER_KIND_TERM, term=folder_name)
432      new_entry.category.append(folder_category)
433
434    return self.__upload(new_entry, ms, auth_token=auth_token, **kwargs)
435
436  UploadAttachment = upload_attachment
437
438  def download_attachment(self, uri_or_entry, file_path):
439    """Downloads an attachment file to disk.
440
441    Args:
442      uri_or_entry: string The full URL to download the file from.
443      file_path: string The full path to save the file to.
444
445    Raises:
446      gdata.client.RequestError: on error response from server.
447    """
448    uri = uri_or_entry
449    if isinstance(uri_or_entry, gdata.sites.data.ContentEntry):
450      uri = uri_or_entry.content.src
451
452    f = open(file_path, 'wb')
453    try:
454      f.write(self._get_file_content(uri))
455    except gdata.client.RequestError, e:
456      f.close()
457      raise e
458    f.flush()
459    f.close()
460
461  DownloadAttachment = download_attachment