mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-28 18:01:36 +00:00
539 lines
24 KiB
Python
539 lines
24 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# Copyright (C) 2011 Google Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""CalendarClient extends the GDataService to streamline Google Calendar operations.
|
|
|
|
CalendarService: Provides methods to query feeds and manipulate items. Extends
|
|
GDataService.
|
|
|
|
DictionaryToParamList: Function which converts a dictionary into a list of
|
|
URL arguments (represented as strings). This is a
|
|
utility function used in CRUD operations.
|
|
"""
|
|
|
|
|
|
__author__ = 'alainv (Alain Vongsouvanh)'
|
|
|
|
|
|
import urllib
|
|
import gdata.client
|
|
import gdata.calendar.data
|
|
import atom.data
|
|
import atom.http_core
|
|
import gdata.gauth
|
|
|
|
|
|
DEFAULT_BATCH_URL = ('https://www.google.com/calendar/feeds/default/private'
|
|
'/full/batch')
|
|
|
|
|
|
class CalendarClient(gdata.client.GDClient):
|
|
"""Client for the Google Calendar service."""
|
|
api_version = '2'
|
|
auth_service = 'cl'
|
|
server = "www.google.com"
|
|
contact_list = "default"
|
|
auth_scopes = gdata.gauth.AUTH_SCOPES['cl']
|
|
|
|
def __init__(self, domain=None, auth_token=None, **kwargs):
|
|
"""Constructs a new client for the Calendar API.
|
|
|
|
Args:
|
|
domain: string The Google Apps domain (if any).
|
|
kwargs: The other parameters to pass to the gdata.client.GDClient
|
|
constructor.
|
|
"""
|
|
gdata.client.GDClient.__init__(self, auth_token=auth_token, **kwargs)
|
|
self.domain = domain
|
|
|
|
def get_calendar_feed_uri(self, feed='', projection='full', scheme="https"):
|
|
"""Builds a feed URI.
|
|
|
|
Args:
|
|
projection: The projection to apply to the feed contents, for example
|
|
'full', 'base', 'base/12345', 'full/batch'. Default value: 'full'.
|
|
scheme: The URL scheme such as 'http' or 'https', None to return a
|
|
relative URI without hostname.
|
|
|
|
Returns:
|
|
A feed URI using the given scheme and projection.
|
|
Example: '/calendar/feeds/default/owncalendars/full'.
|
|
"""
|
|
prefix = scheme and '%s://%s' % (scheme, self.server) or ''
|
|
suffix = feed and '/%s/%s' % (feed, projection) or ''
|
|
return '%s/calendar/feeds/default%s' % (prefix, suffix)
|
|
|
|
GetCalendarFeedUri = get_calendar_feed_uri
|
|
|
|
def get_calendar_event_feed_uri(self, calendar='default', visibility='private',
|
|
projection='full', scheme="https"):
|
|
"""Builds a feed URI.
|
|
|
|
Args:
|
|
projection: The projection to apply to the feed contents, for example
|
|
'full', 'base', 'base/12345', 'full/batch'. Default value: 'full'.
|
|
scheme: The URL scheme such as 'http' or 'https', None to return a
|
|
relative URI without hostname.
|
|
|
|
Returns:
|
|
A feed URI using the given scheme and projection.
|
|
Example: '/calendar/feeds/default/private/full'.
|
|
"""
|
|
prefix = scheme and '%s://%s' % (scheme, self.server) or ''
|
|
return '%s/calendar/feeds/%s/%s/%s' % (prefix, calendar,
|
|
visibility, projection)
|
|
|
|
GetCalendarEventFeedUri = get_calendar_event_feed_uri
|
|
|
|
def get_calendars_feed(self, uri,
|
|
desired_class=gdata.calendar.data.CalendarFeed,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains a calendar feed.
|
|
|
|
Args:
|
|
uri: The uri of the calendar feed to request.
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarFeed.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
return self.get_feed(uri, auth_token=auth_token,
|
|
desired_class=desired_class, **kwargs)
|
|
|
|
GetCalendarsFeed = get_calendars_feed
|
|
|
|
def get_own_calendars_feed(self,
|
|
desired_class=gdata.calendar.data.CalendarFeed,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains a feed containing the calendars owned by the current user.
|
|
|
|
Args:
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarFeed.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
return self.GetCalendarsFeed(uri=self.GetCalendarFeedUri(feed='owncalendars'),
|
|
desired_class=desired_class, auth_token=auth_token,
|
|
**kwargs)
|
|
|
|
GetOwnCalendarsFeed = get_own_calendars_feed
|
|
|
|
def get_all_calendars_feed(self, desired_class=gdata.calendar.data.CalendarFeed,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains a feed containing all the ccalendars the current user has access to.
|
|
|
|
Args:
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarFeed.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
return self.GetCalendarsFeed(uri=self.GetCalendarFeedUri(feed='allcalendars'),
|
|
desired_class=desired_class, auth_token=auth_token,
|
|
**kwargs)
|
|
|
|
GetAllCalendarsFeed = get_all_calendars_feed
|
|
|
|
def get_calendar_entry(self, uri, desired_class=gdata.calendar.data.CalendarEntry,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains a single calendar entry.
|
|
|
|
Args:
|
|
uri: The uri of the desired calendar entry.
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarEntry.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
return self.get_entry(uri, auth_token=auth_token, desired_class=desired_class,
|
|
**kwargs)
|
|
|
|
GetCalendarEntry = get_calendar_entry
|
|
|
|
def get_calendar_event_feed(self, uri=None,
|
|
desired_class=gdata.calendar.data.CalendarEventFeed,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains a feed of events for the desired calendar.
|
|
|
|
Args:
|
|
uri: The uri of the desired calendar entry.
|
|
Defaults to https://www.google.com/calendar/feeds/default/private/full.
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarEventFeed.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
uri = uri or self.GetCalendarEventFeedUri()
|
|
return self.get_feed(uri, auth_token=auth_token,
|
|
desired_class=desired_class, **kwargs)
|
|
|
|
GetCalendarEventFeed = get_calendar_event_feed
|
|
|
|
def get_event_entry(self, uri, desired_class=gdata.calendar.data.CalendarEventEntry,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains a single event entry.
|
|
|
|
Args:
|
|
uri: The uri of the desired calendar event entry.
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarEventEntry.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
return self.get_entry(uri, auth_token=auth_token, desired_class=desired_class,
|
|
**kwargs)
|
|
|
|
GetEventEntry = get_event_entry
|
|
|
|
def get_calendar_acl_feed(self, uri='https://www.google.com/calendar/feeds/default/acl/full',
|
|
desired_class=gdata.calendar.data.CalendarAclFeed,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains an Access Control List feed.
|
|
|
|
Args:
|
|
uri: The uri of the desired Acl feed.
|
|
Defaults to https://www.google.com/calendar/feeds/default/acl/full.
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarAclFeed.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
return self.get_feed(uri, auth_token=auth_token, desired_class=desired_class,
|
|
**kwargs)
|
|
|
|
GetCalendarAclFeed = get_calendar_acl_feed
|
|
|
|
def get_calendar_acl_entry(self, uri, desired_class=gdata.calendar.data.CalendarAclEntry,
|
|
auth_token=None, **kwargs):
|
|
"""Obtains a single Access Control List entry.
|
|
|
|
Args:
|
|
uri: The uri of the desired Acl feed.
|
|
desired_class: class descended from atom.core.XmlElement to which a
|
|
successful response should be converted. If there is no
|
|
converter function specified (desired_class=None) then the
|
|
desired_class will be used in calling the
|
|
atom.core.parse function. If neither
|
|
the desired_class nor the converter is specified, an
|
|
HTTP reponse object will be returned. Defaults to
|
|
gdata.calendar.data.CalendarAclEntry.
|
|
auth_token: An object which sets the Authorization HTTP header in its
|
|
modify_request method. Recommended classes include
|
|
gdata.gauth.ClientLoginToken and gdata.gauth.AuthSubToken
|
|
among others. Represents the current user. Defaults to None
|
|
and if None, this method will look for a value in the
|
|
auth_token member of SpreadsheetsClient.
|
|
"""
|
|
return self.get_entry(uri, auth_token=auth_token, desired_class=desired_class,
|
|
**kwargs)
|
|
|
|
GetCalendarAclEntry = get_calendar_acl_entry
|
|
|
|
def insert_calendar(self, new_calendar, insert_uri=None, auth_token=None, **kwargs):
|
|
"""Adds an new calendar to Google Calendar.
|
|
|
|
Args:
|
|
new_calendar: atom.Entry or subclass A new calendar which is to be added to
|
|
Google Calendar.
|
|
insert_uri: the URL to post new contacts to the feed
|
|
url_params: dict (optional) Additional URL parameters to be included
|
|
in the insertion request.
|
|
escape_params: boolean (optional) If true, the url_parameters will be
|
|
escaped before they are included in the request.
|
|
|
|
Returns:
|
|
On successful insert, an entry containing the contact created
|
|
On failure, a RequestError is raised of the form:
|
|
{'status': HTTP status code from server,
|
|
'reason': HTTP reason from the server,
|
|
'body': HTTP body of the server's response}
|
|
"""
|
|
insert_uri = insert_uri or self.GetCalendarFeedUri(feed='owncalendars')
|
|
return self.Post(new_calendar, insert_uri,
|
|
auth_token=auth_token, **kwargs)
|
|
|
|
InsertCalendar = insert_calendar
|
|
|
|
def insert_calendar_subscription(self, calendar, insert_uri=None,
|
|
auth_token=None, **kwargs):
|
|
"""Subscribes the authenticated user to the provided calendar.
|
|
|
|
Args:
|
|
calendar: The calendar to which the user should be subscribed.
|
|
url_params: dict (optional) Additional URL parameters to be included
|
|
in the insertion request.
|
|
escape_params: boolean (optional) If true, the url_parameters will be
|
|
escaped before they are included in the request.
|
|
|
|
Returns:
|
|
On successful insert, an entry containing the subscription created
|
|
On failure, a RequestError is raised of the form:
|
|
{'status': HTTP status code from server,
|
|
'reason': HTTP reason from the server,
|
|
'body': HTTP body of the server's response}
|
|
"""
|
|
insert_uri = insert_uri or self.GetCalendarFeedUri(feed='allcalendars')
|
|
return self.Post(calendar, insert_uri, auth_token=auth_token, **kwargs)
|
|
|
|
InsertCalendarSubscription = insert_calendar_subscription
|
|
|
|
def insert_event(self, new_event, insert_uri=None, auth_token=None, **kwargs):
|
|
"""Adds an new event to Google Calendar.
|
|
|
|
Args:
|
|
new_event: atom.Entry or subclass A new event which is to be added to
|
|
Google Calendar.
|
|
insert_uri: the URL to post new contacts to the feed
|
|
url_params: dict (optional) Additional URL parameters to be included
|
|
in the insertion request.
|
|
escape_params: boolean (optional) If true, the url_parameters will be
|
|
escaped before they are included in the request.
|
|
|
|
Returns:
|
|
On successful insert, an entry containing the contact created
|
|
On failure, a RequestError is raised of the form:
|
|
{'status': HTTP status code from server,
|
|
'reason': HTTP reason from the server,
|
|
'body': HTTP body of the server's response}
|
|
"""
|
|
insert_uri = insert_uri or self.GetCalendarEventFeedUri()
|
|
return self.Post(new_event, insert_uri,
|
|
auth_token=auth_token, **kwargs)
|
|
|
|
|
|
InsertEvent = insert_event
|
|
|
|
def insert_acl_entry(self, new_acl_entry,
|
|
insert_uri = 'https://www.google.com/calendar/feeds/default/acl/full',
|
|
auth_token=None, **kwargs):
|
|
"""Adds an new Acl entry to Google Calendar.
|
|
|
|
Args:
|
|
new_acl_event: atom.Entry or subclass A new acl which is to be added to
|
|
Google Calendar.
|
|
insert_uri: the URL to post new contacts to the feed
|
|
url_params: dict (optional) Additional URL parameters to be included
|
|
in the insertion request.
|
|
escape_params: boolean (optional) If true, the url_parameters will be
|
|
escaped before they are included in the request.
|
|
|
|
Returns:
|
|
On successful insert, an entry containing the contact created
|
|
On failure, a RequestError is raised of the form:
|
|
{'status': HTTP status code from server,
|
|
'reason': HTTP reason from the server,
|
|
'body': HTTP body of the server's response}
|
|
"""
|
|
return self.Post(new_acl_entry, insert_uri, auth_token=auth_token, **kwargs)
|
|
|
|
InsertAclEntry = insert_acl_entry
|
|
|
|
def execute_batch(self, batch_feed, url, desired_class=None):
|
|
"""Sends a batch request feed to the server.
|
|
|
|
Args:
|
|
batch_feed: gdata.contacts.CalendarEventFeed A feed containing batch
|
|
request entries. Each entry contains the operation to be performed
|
|
on the data contained in the entry. For example an entry with an
|
|
operation type of insert will be used as if the individual entry
|
|
had been inserted.
|
|
url: str The batch URL to which these operations should be applied.
|
|
converter: Function (optional) The function used to convert the server's
|
|
response to an object.
|
|
|
|
Returns:
|
|
The results of the batch request's execution on the server. If the
|
|
default converter is used, this is stored in a ContactsFeed.
|
|
"""
|
|
return self.Post(batch_feed, url, desired_class=desired_class)
|
|
|
|
ExecuteBatch = execute_batch
|
|
|
|
def update(self, entry, auth_token=None, **kwargs):
|
|
"""Edits the entry on the server by sending the XML for this entry.
|
|
|
|
Performs a PUT and converts the response to a new entry object with a
|
|
matching class to the entry passed in.
|
|
|
|
Args:
|
|
entry:
|
|
auth_token:
|
|
|
|
Returns:
|
|
A new Entry object of a matching type to the entry which was passed in.
|
|
"""
|
|
return gdata.client.GDClient.Update(self, entry, auth_token=auth_token,
|
|
force=True, **kwargs)
|
|
|
|
Update = update
|
|
|
|
|
|
class CalendarEventQuery(gdata.client.Query):
|
|
"""
|
|
Create a custom Calendar Query
|
|
|
|
Full specs can be found at: U{Calendar query parameters reference
|
|
<http://code.google.com/apis/calendar/data/2.0/reference.html#Parameters>}
|
|
"""
|
|
|
|
def __init__(self, feed=None, ctz=None, fields=None, futureevents=None,
|
|
max_attendees=None, orderby=None, recurrence_expansion_start=None,
|
|
recurrence_expansion_end=None, singleevents=None, showdeleted=None,
|
|
showhidden=None, sortorder=None, start_min=None, start_max=None,
|
|
updated_min=None, **kwargs):
|
|
"""
|
|
@param max_results: The maximum number of entries to return. If you want
|
|
to receive all of the contacts, rather than only the default maximum, you
|
|
can specify a very large number for max-results.
|
|
@param start-index: The 1-based index of the first result to be retrieved.
|
|
@param updated-min: The lower bound on entry update dates.
|
|
@param group: Constrains the results to only the contacts belonging to the
|
|
group specified. Value of this parameter specifies group ID
|
|
@param orderby: Sorting criterion. The only supported value is
|
|
lastmodified.
|
|
@param showdeleted: Include deleted contacts in the returned contacts feed
|
|
@pram sortorder: Sorting order direction. Can be either ascending or
|
|
descending.
|
|
@param requirealldeleted: Only relevant if showdeleted and updated-min
|
|
are also provided. It dictates the behavior of the server in case it
|
|
detects that placeholders of some entries deleted since the point in
|
|
time specified as updated-min may have been lost.
|
|
"""
|
|
gdata.client.Query.__init__(self, **kwargs)
|
|
self.ctz = ctz
|
|
self.fields = fields
|
|
self.futureevents = futureevents
|
|
self.max_attendees = max_attendees
|
|
self.orderby = orderby
|
|
self.recurrence_expansion_start = recurrence_expansion_start
|
|
self.recurrence_expansion_end = recurrence_expansion_end
|
|
self.singleevents = singleevents
|
|
self.showdeleted = showdeleted
|
|
self.showhidden = showhidden
|
|
self.sortorder = sortorder
|
|
self.start_min = start_min
|
|
self.start_max = start_max
|
|
self.updated_min = updated_min
|
|
|
|
def modify_request(self, http_request):
|
|
if self.ctz:
|
|
gdata.client._add_query_param('ctz', self.ctz, http_request)
|
|
if self.fields:
|
|
gdata.client._add_query_param('fields', self.fields, http_request)
|
|
if self.futureevents:
|
|
gdata.client._add_query_param('futureevents', self.futureevents, http_request)
|
|
if self.max_attendees:
|
|
gdata.client._add_query_param('max-attendees', self.max_attendees, http_request)
|
|
if self.orderby:
|
|
gdata.client._add_query_param('orderby', self.orderby, http_request)
|
|
if self.recurrence_expansion_start:
|
|
gdata.client._add_query_param('recurrence-expansion-start',
|
|
self.recurrence_expansion_start, http_request)
|
|
if self.recurrence_expansion_end:
|
|
gdata.client._add_query_param('recurrence-expansion-end',
|
|
self.recurrence_expansion_end, http_request)
|
|
if self.singleevents:
|
|
gdata.client._add_query_param('singleevents', self.singleevents, http_request)
|
|
if self.showdeleted:
|
|
gdata.client._add_query_param('showdeleted', self.showdeleted, http_request)
|
|
if self.showhidden:
|
|
gdata.client._add_query_param('showhidden', self.showhidden, http_request)
|
|
if self.sortorder:
|
|
gdata.client._add_query_param('sortorder', self.sortorder, http_request)
|
|
if self.start_min:
|
|
gdata.client._add_query_param('start-min', self.start_min, http_request)
|
|
if self.start_max:
|
|
gdata.client._add_query_param('start-max', self.start_max, http_request)
|
|
if self.updated_min:
|
|
gdata.client._add_query_param('updated-min', self.updated_min, http_request)
|
|
gdata.client.Query.modify_request(self, http_request)
|
|
|
|
ModifyRequest = modify_request
|
|
|
|
|
|
|