1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
|
#!/usr/bin/python
#
# Copyright (C) 2007 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.
#
#
# This sample uses the Google Spreadsheets data API and the Google
# Calendar data API. The script pulls a list of birthdays from a
# Google Spreadsheet and inserts them as webContent events in the
# user's Google Calendar.
#
# The script expects a certain format in the spreadsheet: Name,
# Birthday, Photo URL, and Edit URL as headers. Expected format
# of the birthday is: MM/DD. Edit URL is to be left blank by the
# user - the script uses this column to determine whether to insert
# a new event or to update an event at the URL.
#
# See the spreadsheet below for an example:
# http://spreadsheets.google.com/pub?key=pfMX-JDVnx47J0DxqssIQHg
#
__author__ = 'api.stephaniel@google.com (Stephanie Liu)'
try:
from xml.etree import ElementTree # for Python 2.5 users
except:
from elementtree import ElementTree
import gdata.spreadsheet.service
import gdata.calendar.service
import gdata.calendar
import gdata.service
import atom.service
import gdata.spreadsheet
import atom
import string
import time
import datetime
import getopt
import getpass
import sys
class BirthdaySample:
# CONSTANTS: Expected column headers: name, birthday, photourl, editurl &
# default calendar reminder set to 2 days
NAME = "name"
BIRTHDAY = "birthday"
PHOTO_URL = "photourl"
EDIT_URL = "editurl"
REMINDER = 60 * 24 * 2 # minutes
def __init__(self, email, password):
""" Initializes spreadsheet and calendar clients.
Creates SpreadsheetsService and CalendarService objects and
authenticates to each with ClientLogin. For more information
about ClientLogin authentication:
http://code.google.com/apis/accounts/AuthForInstalledApps.html
Args:
email: string
password: string
"""
self.s_client = gdata.spreadsheet.service.SpreadsheetsService()
self.s_client.email = email
self.s_client.password = password
self.s_client.source = 'exampleCo-birthdaySample-1'
self.s_client.ProgrammaticLogin()
self.c_client = gdata.calendar.service.CalendarService()
self.c_client.email = email
self.c_client.password = password
self.c_client.source = 'exampleCo-birthdaySample-1'
self.c_client.ProgrammaticLogin()
def _PrintFeed(self, feed):
""" Prints out Spreadsheet feeds in human readable format.
Generic function taken from spreadsheetsExample.py.
Args:
feed: SpreadsheetsCellsFeed, SpreadsheetsListFeed,
SpreadsheetsWorksheetsFeed, or SpreadsheetsSpreadsheetsFeed
"""
for i, entry in enumerate(feed.entry):
if isinstance(feed, gdata.spreadsheet.SpreadsheetsCellsFeed):
print '%s %s\n' % (entry.title.text, entry.content.text)
elif isinstance(feed, gdata.spreadsheet.SpreadsheetsListFeed):
print '%s %s %s\n' % (i, entry.title.text, entry.content.text)
else:
print '%s %s\n' % (i, entry.title.text)
def _PromptForSpreadsheet(self):
""" Prompts user to select spreadsheet.
Gets and displays titles of all spreadsheets for user to
select. Generic function taken from spreadsheetsExample.py.
Args:
none
Returns:
spreadsheet ID that the user selected: string
"""
feed = self.s_client.GetSpreadsheetsFeed()
self._PrintFeed(feed)
input = raw_input('\nSelection: ')
# extract and return the spreadsheet ID
return feed.entry[string.atoi(input)].id.text.rsplit('/', 1)[1]
def _PromptForWorksheet(self, key):
""" Prompts user to select desired worksheet.
Gets and displays titles of all worksheets for user to
select. Generic function taken from spreadsheetsExample.py.
Args:
key: string
Returns:
the worksheet ID that the user selected: string
"""
feed = self.s_client.GetWorksheetsFeed(key)
self._PrintFeed(feed)
input = raw_input('\nSelection: ')
# extract and return the worksheet ID
return feed.entry[string.atoi(input)].id.text.rsplit('/', 1)[1]
def _AddReminder(self, event, minutes):
""" Adds a reminder to a calendar event.
This function sets the reminder attribute of the CalendarEventEntry.
The script sets it to 2 days by default, and this value is not
settable by the user. However, it can easily be changed to take this
option.
Args:
event: CalendarEventEntry
minutes: int
Returns:
the updated event: CalendarEventEntry
"""
for a_when in event.when:
if len(a_when.reminder) > 0:
a_when.reminder[0].minutes = minutes
else:
a_when.reminder.append(gdata.calendar.Reminder(minutes=minutes))
return self.c_client.UpdateEvent(event.GetEditLink().href, event)
def _CreateBirthdayWebContentEvent(self, name, birthday, photo_url):
""" Create the birthday web content event.
This function creates and populates a CalendarEventEntry. webContent
specific attributes are set. To learn more about the webContent
format:
http://www.google.com/support/calendar/bin/answer.py?answer=48528
Args:
name: string
birthday: string - expected format (MM/DD)
photo_url: string
Returns:
the webContent CalendarEventEntry
"""
title = "%s's Birthday!" % name
content = "It's %s's Birthday!" % name
month = string.atoi(birthday.split("/")[0])
day = string.atoi(birthday.split("/")[1])
# Get current year
year = time.ctime()[-4:]
year = string.atoi(year)
# Calculate the "end date" for the all day event
start_time = datetime.date(year, month, day)
one_day = datetime.timedelta(days=1)
end_time = start_time + one_day
start_time_str = start_time.strftime("%Y-%m-%d")
end_time_str = end_time.strftime("%Y-%m-%d")
# Create yearly recurrence rule
recurrence_data = ("DTSTART;VALUE=DATE:%s\r\n"
"DTEND;VALUE=DATE:%s\r\n"
"RRULE:FREQ=YEARLY;WKST=SU\r\n" %
(start_time.strftime("%Y%m%d"), end_time.strftime("%Y%m%d")))
web_rel = "http://schemas.google.com/gCal/2005/webContent"
icon_href = "http://www.perstephanie.com/images/birthdayicon.gif"
icon_type = "image/gif"
extension_text = (
'gCal:webContent xmlns:gCal="http://schemas.google.com/gCal/2005"'
' url="%s" width="300" height="225"' % (photo_url))
event = gdata.calendar.CalendarEventEntry()
event.title = atom.Title(text=title)
event.content = atom.Content(text=content)
event.recurrence = gdata.calendar.Recurrence(text=recurrence_data)
event.when.append(gdata.calendar.When(start_time=start_time_str,
end_time=end_time_str))
# Adding the webContent specific XML
event.link.append(atom.Link(rel=web_rel, title=title, href=icon_href,
link_type=icon_type))
event.link[0].extension_elements.append(
atom.ExtensionElement(extension_text))
return event
def _InsertBirthdayWebContentEvent(self, event):
""" Insert event into the authenticated user's calendar.
Args:
event: CalendarEventEntry
Returns:
the newly created CalendarEventEntry
"""
edit_uri = '/calendar/feeds/default/private/full'
return self.c_client.InsertEvent(event, edit_uri)
def Run(self):
""" Run sample.
TODO: add exception handling
Args:
none
"""
key_id = self._PromptForSpreadsheet()
wksht_id = self._PromptForWorksheet(key_id)
feed = self.s_client.GetListFeed(key_id, wksht_id)
found_name = False
found_birthday = False
found_photourl = False
found_editurl = False
# Check to make sure all headers are present
# Need to find at least one instance of name, birthday, photourl
# editurl
if len(feed.entry) > 0:
for name, custom in feed.entry[0].custom.iteritems():
if custom.column == self.NAME:
found_name = True
elif custom.column == self.BIRTHDAY:
found_birthday = True
elif custom.column == self.PHOTO_URL:
found_photourl = True
elif custom.column == self.EDIT_URL:
found_editurl = True
if not found_name and found_birthday and found_photourl and found_editurl:
print ("ERROR - Unexpected number of column headers. Should have: %s,"
" %s, %s, and %s." % (self.NAME, self.BIRTHDAY, self.PHOTO_URL,
self.EDIT_URL))
sys.exit(1)
# For every row in the spreadsheet, grab all the data and either insert
# a new event into the calendar, or update the existing event
# Create dict to represent the row data to update edit link back to
# Spreadsheet
for entry in feed.entry:
d = {}
input_valid = True
for name, custom in entry.custom.iteritems():
d[custom.column] = custom.text
month = int(d[self.BIRTHDAY].split("/")[0])
day = int(d[self.BIRTHDAY].split("/")[1])
# Some input checking. Script will allow the insert to continue with
# a missing name value.
if d[self.NAME] is None:
d[self.NAME] = " "
if d[self.PHOTO_URL] is None:
input_valid = False
if d[self.BIRTHDAY] is None:
input_valid = False
elif not 1 <= month <= 12 or not 1 <= day <= 31:
input_valid = False
if d[self.EDIT_URL] is None and input_valid:
event = self._CreateBirthdayWebContentEvent(d[self.NAME],
d[self.BIRTHDAY], d[self.PHOTO_URL])
event = self._InsertBirthdayWebContentEvent(event)
event = self._AddReminder(event, self.REMINDER)
print "Added %s's birthday!" % d[self.NAME]
elif input_valid: # Event already exists
edit_link = d[self.EDIT_URL]
event = self._CreateBirthdayWebContentEvent(d[self.NAME],
d[self.BIRTHDAY], d[self.PHOTO_URL])
event = self.c_client.UpdateEvent(edit_link, event)
event = self._AddReminder(event, self.REMINDER)
print "Updated %s's birthday!" % d[self.NAME]
if input_valid:
d[self.EDIT_URL] = event.GetEditLink().href
self.s_client.UpdateRow(entry, d)
else:
print "Warning - Skipping row, missing valid input."
def main():
email = raw_input("Please enter your email: ")
password = getpass.getpass("Please enter your password: ")
sample = BirthdaySample(email, password)
sample.Run()
if __name__ == '__main__':
main()
|