def AddPhoto(filename, summary, title, imageFormat='jpeg', timestamp=None): if isImageFile(filename) == False: log('Not Image: %s', filename) OTHER_FILES.append(filename) return log('Uploading photo: %s', filename) url = '/data/feed/api/user/%s/albumid/%s?kind=photo' % (USERNAME, ALBUM_ID) metadata = gdata.photos.PhotoEntry() metadata.title = atom.Title(text=title) metadata.summary = atom.Summary(text=summary, summary_type='text') if UPDATE_FILE_METADATA == True and timestamp is not None: metadata.timestamp = gdata.photos.Timestamp(text=timestamp) metadata.published = atom.Published( text=metadata.timestamp.isoformat()) metadata.updated = atom.Updated(text=metadata.timestamp.isoformat()) UpdateFileMetadata(filename, metadata.timestamp.datetime()) if DRY_RUN == False: try: photo = gd_client.InsertPhoto( \ url, metadata, filename, 'image/' + imageFormat) if photo is None: ERRORS.append('Photo may not have been uploaded: ' + filename) except gdata.photos.service.GooglePhotosException: ERRORS.append('Photo may not have been uploaded: ' + filename)
def upload_insert(self, client, album_id, options): """Uploads a new photo by inserting it into an album. """ if options.dryrun: return album_url = '%s/%s' % (_ALBUM_URL, album_id) new_photo = gdata.photos.PhotoEntry() new_photo.title = atom.Title(text=self.title) comment = imageutils.get_photo_caption(self.photo, options.captiontemplate) if comment: new_photo.summary = atom.Summary(text=comment, summary_type='text') new_photo.media = gdata.media.Group() new_photo.media.keywords = gdata.media.Keywords( text=', '.join(self.get_export_keywords(options))) if options.gps and self.photo.gps: new_photo.geo = gdata.geo.Where() new_photo.geo.Point = gdata.geo.Point() new_photo.geo.Point.pos = gdata.geo.Pos( text='%.6f %.6f' % (self.photo.gps.latitude, self.photo.gps.longitude)) # TODO(tilmansp): For some reason, this does not seem to work, and # all newly inserted images need a second update cycle to fix the # timestamp. if self.photo.date: new_photo.timestamp = gdata.photos.Timestamp( text=get_picasaweb_date(self.photo.date)) client.throttle() self.picasa_photo = client.gd_client.InsertPhoto( album_url, new_photo, self.photo.image_path, content_type=get_content_type(self.photo.image_path))
def testMedia1(self): # Create media-only ms = gdata.MediaSource() ms.setFile(test_image_location, 'image/jpeg') media_entry = self.gd_client.Post(None, self.album_entry.GetFeedLink().href, media_source=ms) self.assertTrue(media_entry is not None) self.assertTrue(isinstance(media_entry, gdata.GDataEntry)) self.assertTrue(media_entry.IsMedia()) # Update media & metadata ms = gdata.MediaSource() ms.setFile(test_image_location, 'image/jpeg') media_entry.summary = atom.Summary(text='Test Image') media_entry2 = self.gd_client.Put(media_entry, media_entry.GetEditLink().href, media_source=ms) self.assertTrue(media_entry2 is not None) self.assertTrue(isinstance(media_entry2, gdata.GDataEntry)) self.assertTrue(media_entry2.IsMedia()) self.assertTrue(media_entry2.summary.text == 'Test Image') # Read media binary imageSource = self.gd_client.GetMedia(media_entry2.GetMediaURL()) self.assertTrue(isinstance(imageSource, gdata.MediaSource)) self.assertTrue(imageSource.content_type == 'image/jpeg') self.assertTrue(imageSource.content_length) imageData = imageSource.file_handle.read() self.assertTrue(imageData) # Delete entry response = self.gd_client.Delete(media_entry2.GetEditLink().href) self.assertTrue(response)
def testMedia2(self): # Create media & metadata ms = gdata.MediaSource() ms.setFile(test_image_location, 'image/jpeg') new_media_entry = gdata.GDataEntry() new_media_entry.title = atom.Title(text='testimage1.jpg') new_media_entry.summary = atom.Summary(text='Test Image') new_media_entry.category.append( atom.Category(scheme='http://schemas.google.com/g/2005#kind', term='http://schemas.google.com/photos/2007#photo')) media_entry = self.gd_client.Post(new_media_entry, self.album_entry.GetFeedLink().href, media_source=ms) self.assertTrue(media_entry is not None) self.assertTrue(isinstance(media_entry, gdata.GDataEntry)) self.assertTrue(media_entry.IsMedia()) self.assertTrue(media_entry.summary.text == 'Test Image') # Update media only ms = gdata.MediaSource() ms.setFile(test_image_location, 'image/jpeg') media_entry = self.gd_client.Put(None, media_entry.GetEditMediaLink().href, media_source=ms) self.assertTrue(media_entry is not None) self.assertTrue(isinstance(media_entry, gdata.GDataEntry)) self.assertTrue(media_entry.IsMedia()) # Delete entry response = self.gd_client.Delete(media_entry.GetEditLink().href) self.assertTrue(response)
def upload_insert(self, client, album_id, options): """Uploads a new photo by inserting it into an album. """ if options.dryrun: return album_url = '%s/%s' % (_ALBUM_URL, album_id) new_photo = gdata.photos.PhotoEntry() new_photo.title = atom.Title(text=self.title) # Combine title and description because PicasaWeb does not show the # title anywhere. comment = imageutils.get_photo_caption(self.photo, options.captiontemplate) export_keywords = self.get_export_keywords(options) photo_gps = self.photo.gps if comment: new_photo.summary = atom.Summary(text=comment, summary_type='text') new_photo.media = gdata.media.Group() new_photo.media.keywords = gdata.media.Keywords( text=', '.join(export_keywords)) if options.gps and photo_gps: new_photo.geo = gdata.geo.Where() new_photo.geo.Point = gdata.geo.Point() new_photo.geo.Point.pos = gdata.geo.Pos( text='%.6f %.6f' % (photo_gps.latitude, photo_gps.longitude)) client.throttle() self.picasa_photo = client.gd_client.InsertPhoto( album_url, new_photo, self.photo.image_path, content_type=get_content_type(self.photo.image_path))
def new(self, title='New Calendar', summary='New Calendar', place='A-Server', color='#2952A3', timezone='Africa/Cairo', hidden='false'): """ Creates a new calendar using the given parameters in the user's calendars. @param title: string for the title of the new calendar to be created, default is "New Calendar" @param summary: string for the summary of the new calendar to be created, default is "New Calendar" @param place: string for the default location of the new calendar @param color: string for the color in hex for the online interface of the calendar, default is google's "blue" default for new calendars @param timezone: string for the time zone of the calendar @param hidden: boolean to decide whether the calendar is to be hidden or visible in the online interface """ calendar = gdata.calendar.CalendarListEntry() calendar.title = atom.Title(text=title) calendar.summary = atom.Summary(text=summary) calendar.where = gdata.calendar.Where(value_string=place) calendar.color = gdata.calendar.Color(value=color) calendar.timezone = gdata.calendar.Timezone(value=timezone) calendar.hidden = gdata.calendar.Hidden(value=hidden) new_calendar = self._client.InsertCalendar(new_calendar=calendar) title = cleanString(title) self.calendars._addCalendar(self, self._client, new_calendar) q.logger.log('Calendar %s added'%title, 2) return new_calendar
def upload(gd_client, localPath, album, fileName): print("Uploading " + localPath) contentType = getContentType(fileName) if contentType.startswith('image/'): isImage = True picasa_photo = gdata.photos.PhotoEntry() else: size = os.path.getsize(localPath) # tested by cpbotha on 2013-05-24 # this limit still exists if size > PICASA_MAX_VIDEO_SIZE_BYTES: print("Video file too big to upload: " + str(size) + " > " + str(PICASA_MAX_VIDEO_SIZE_BYTES)) return isImage = False picasa_photo = VideoEntry() picasa_photo.title = atom.Title(text=fileName) picasa_photo.summary = atom.Summary(text='', summary_type='text') delay = 1 while True: try: if isImage: gd_client.InsertPhoto(album, picasa_photo, localPath, content_type=contentType) else: gd_client.InsertVideo(album, picasa_photo, localPath, content_type=contentType) break except gdata.photos.service.GooglePhotosException as e: print("Got exception " + str(e)) print("retrying in " + str(delay) + " seconds") time.sleep(delay) delay = delay * 2
def createCalendar(self, title, summary, where, Color='#2952A3',timezone): # Create the calendar calendar = gdata.calendar.CalendarListEntry() calendar.title = atom.Title(text=title) calendar.summary = atom.Summary(text=summary) calendar.where = gdata.calendar.Where(value_string=where) calendar.color = gdata.calendar.Color(value=Color) calendar.timezone = gdata.calendar.Timezone(value=timezone) calendar.hidden = gdata.calendar.Hidden(value='false') new_calendar = calendar_service.InsertCalendar(new_calendar=calendar)
def __post(self, author, title, summary, content, category, draft, entryXml): """ to post the content to the server @param author: Author name @type author: String @param title: Title of the content @type title: String @param summary: Summary of the content @type summary: String @param content: Content @type content: String @param draft: Type of the document: @type draft: boolean @param entryXml: extra entry @type entryXml: String @rtype: (Atom Entry, String) @return: entry, httpResponse """ # create/update the atom entry if entryXml == None: entry = atom.Entry() entryUri = self.entryUri else: entry = atom.EntryFromString(entryXml) entryUri = entry.GetEditLink().href entry.author = [atom.Author(text=author)] entry.title = atom.Title(text=title) entry.summary = atom.Summary(text=summary) entry.content = atom.Content(content_type="html", text=unicode(content, "utf-8")) if category != "": entry.category = atom.Category(term=category) if draft: entry.control = atom.Control(draft=atom.Draft(text="yes")) else: entry.control = atom.Control(draft=atom.Draft(text="no")) # setup the http headers for authorisation extraHeaders = {"Slug": title} extraHeaders.update(self.authHeaders) # use POST or PUT depending on whether it is a new entry or an update if entryXml != None: publishFunc = self.atomService.Put else: publishFunc = self.atomService.Post self.__checkNoProxy(entryUri) httpResponse = publishFunc(data=entry, uri=entryUri, extra_headers=extraHeaders) self.__resetProxy() return entry, httpResponse
def testInsertPhotoUpdateBlobAndDelete(self): new_entry = gdata.photos.PhotoEntry() new_entry.title = atom.Title(text='a_test_image') new_entry.summary = atom.Summary(text='Just a test.') new_entry.category.append(atom.Category( scheme='http://schemas.google.com/g/2005#kind', term='http://schemas.google.com/photos/2007#photo')) entry = self.client.InsertPhoto(self.test_album, new_entry, test_image_location, content_type='image/jpeg') self.assert_(entry.id.text) updated_entry = self.client.UpdatePhotoBlob(entry, test_image_location) self.assert_(entry.GetEditLink().href != updated_entry.GetEditLink().href) self.client.Delete(updated_entry)
def upload(gd_client, localPath, album, fileName, no_resize): print "Uploading " + localPath contentType = getContentType(fileName) if contentType.startswith('image/'): if no_resize: imagePath = localPath else: imagePath = shrinkIfNeeded(localPath, PICASA_MAX_FREE_IMAGE_DIMENSION) isImage = True picasa_photo = gdata.photos.PhotoEntry() else: size = os.path.getsize(localPath) # tested by cpbotha on 2013-05-24 # this limit still exists if size > PICASA_MAX_VIDEO_SIZE_BYTES: print "## Video file too big to upload: " + str( fileName) + " : " + str(size) + " > " + str( PICASA_MAX_VIDEO_SIZE_BYTES) return imagePath = localPath isImage = False picasa_photo = VideoEntry() picasa_photo.title = atom.Title(text=fileName) picasa_photo.summary = atom.Summary(text='', summary_type='text') delay = 1 while True: try: if isImage: gd_client.InsertPhoto(album, picasa_photo, imagePath, content_type=contentType) else: gd_client.InsertVideo(album, picasa_photo, imagePath, content_type=contentType) break except gdata.photos.service.GooglePhotosException, e: if e.args[0] == 403: print "Refreshing token" gd_client = refresh(gd_client) else: print "Got exception " + str(e) print "retrying in " + str(delay) + " seconds" time.sleep(delay) delay = delay * 2
def __getEntryForDocument(self, queryPath, id): """ @param queryPath: Query to search for the entry @type queryPath: String @param id: Id to be applied to atom feed @type id: String @rtype: ElementTree._Element, or xml_wrapper.ElementWrapper @return entry """ docPath = self.rep.getPathForId(id) # check docPath if docPath.startswith(queryPath): item = self.rep.getItem(docPath) if item.hasHtml: docPath = self.iceContext.fs.splitExt(docPath)[0] + ".htm" title = item.getMeta("title") try: title = title.decode("utf-8") except: msg = "[Can not display title because of an encoding error!]" print "%s\n title='%s' path='%s'\n" % (msg, title, docPath) title = msg content = item.getRendition(".xhtml.body") if content is None: content = "<p>[Not rendered!]</p>" contentElem = ElementTree.XML(content) firstPara = contentElem.find("p") summary = "No summary" if firstPara != None: summary = ElementTree.tostring(firstPara) name = item.name lastModifiedTime = self.iceContext.fs.getModifiedTime( self.rep.getAbsPath(name)) entryDate = datetime.fromtimestamp( lastModifiedTime).isoformat() + 'Z' srcUrl = "http://%s:%s%s" % (self.hostname, self.iceWebPort, docPath) entry = atom.Entry(title=atom.Title(text=title)) entry.id = atom.Id(text="urn:uid:%s" % id) entry.link = [atom.Link(href=srcUrl, rel="alternate")] entry.updated = atom.Updated(text=entryDate) entry.published = atom.Published(text=entryDate) entry.summary = atom.Summary(summary_type="html", text=unicode(summary, "utf-8")) entry.content = atom.Content(content_type="html", text=unicode(content, "utf-8")) return entry else: return None
def testPostUpdateAndDeleteCalendar(self): """Test posting a new calendar, updating it, deleting it""" self.cal_client.ProgrammaticLogin() # New calendar to create title = 'Little League Schedule' description = 'This calendar contains practice and game times' time_zone = 'America/Los_Angeles' hidden = False location = 'Oakland' color = '#2952A3' # Calendar object calendar = gdata.calendar.CalendarListEntry() calendar.title = atom.Title(text=title) calendar.summary = atom.Summary(text=description) calendar.where = gdata.calendar.Where(value_string=location) calendar.color = gdata.calendar.Color(value=color) calendar.timezone = gdata.calendar.Timezone(value=time_zone) if hidden: calendar.hidden = gdata.calendar.Hidden(value='true') else: calendar.hidden = gdata.calendar.Hidden(value='false') # Create calendar new_calendar = self.cal_client.InsertCalendar(new_calendar=calendar) self.assertEquals(title, new_calendar.title.text) self.assertEquals(description, new_calendar.summary.text) self.assertEquals(location, new_calendar.where.value_string) self.assertEquals(color, new_calendar.color.value) self.assertEquals(time_zone, new_calendar.timezone.value) if hidden: self.assertEquals('true', new_calendar.hidden.value) else: self.assertEquals('false', new_calendar.hidden.value) # Update calendar calendar_to_update = self.cal_client.GetCalendarListEntry( new_calendar.id.text) updated_title = 'This is the updated title' calendar_to_update.title.text = updated_title updated_calendar = self.cal_client.UpdateCalendar(calendar_to_update) self.assertEquals(updated_title, updated_calendar.title.text) # Delete calendar calendar_to_delete = self.cal_client.GetCalendarListEntry( new_calendar.id.text) self.cal_client.Delete(calendar_to_delete.GetEditLink().href) return new_calendar
def add_google_calendar(self, title, login, password, color): #Init var color = "#" + color[2:] if not self.googleAccountConnect(login, password) == False: calendar = gdata.calendar.CalendarListEntry() calendar.title = atom.Title(text=title) calendar.summary = atom.Summary(text='') calendar.where = gdata.calendar.Where(value_string='') calendar.color = gdata.calendar.Color(value=color) calendar.timezone = gdata.calendar.Timezone(value='UTC') calendar.hidden = gdata.calendar.Hidden(value='false') #Create the Calendar new_calendar = self.calendar_service.InsertCalendar( new_calendar=calendar) else: print "can't connect"
def InsertPhotoSimple(self, album_or_uri, title, summary, filename_or_handle, content_type='image/jpeg', keywords=None): """Add a photo without constructing a PhotoEntry. Needs authentication, see self.ClientLogin() Arguments: album_or_uri: AlbumFeed or uri of the album where the photo should go title: Photo title summary: Photo summary / description filename_or_handle: A file-like object or file name where the image/video will be read from content_type (optional): Internet media type (a.k.a. mime type) of media object. Currently Google Photos supports these types: o image/bmp o image/gif o image/jpeg o image/png Images will be converted to jpeg on upload. Defaults to `image/jpeg' keywords (optional): a 1) comma separated string or 2) a python list() of keywords (a.k.a. tags) to add to the image. E.g. 1) `dog, vacation, happy' 2) ['dog', 'happy', 'vacation'] Returns: The newly created gdata.photos.PhotoEntry or GooglePhotosException on errors See: http://code.google.com/apis/picasaweb/gdata.html#Add_Album_Manual_Installed [1]: http://en.wikipedia.org/wiki/Unix_epoch """ metadata = gdata.photos.PhotoEntry() metadata.title = atom.Title(text=title) metadata.summary = atom.Summary(text=summary, summary_type='text') if keywords is not None: if isinstance(keywords, list): keywords = ','.join(keywords) metadata.media.keywords = gdata.media.Keywords(text=keywords) return self.InsertPhoto(album_or_uri, metadata, filename_or_handle, content_type)
def InsertAlbum(self, title, summary, location=None, access='public', commenting_enabled='true', timestamp=None): """Add an album. Needs authentication, see self.ClientLogin() Arguments: title: Album title summary: Album summary / description access (optional): `private' or `public'. Public albums are searchable by everyone on the internet. Defaults to `public' commenting_enabled (optional): `true' or `false'. Defaults to `true'. timestamp (optional): A date and time for the album, in milliseconds since Unix epoch[1] UTC. Defaults to now. Returns: The newly created gdata.photos.AlbumEntry See: http://code.google.com/apis/picasaweb/gdata.html#Add_Album_Manual_Installed [1]: http://en.wikipedia.org/wiki/Unix_epoch """ album = gdata.photos.AlbumEntry() album.title = atom.Title(text=title, title_type='text') album.summary = atom.Summary(text=summary, summary_type='text') if location is not None: album.location = gdata.photos.Location(text=location) album.access = gdata.photos.Access(text=access) if commenting_enabled in ('true', 'false'): album.commentingEnabled = gdata.photos.CommentingEnabled( text=commenting_enabled) if timestamp is None: timestamp = '%i' % int(time.time() * 1000) album.timestamp = gdata.photos.Timestamp(text=timestamp) try: return self.Post(album, uri=self.userUri % self.email, converter=gdata.photos.AlbumEntryFromString) except gdata.service.RequestError, e: raise GooglePhotosException(e.args[0])
def _InsertCalendar(self, title='Little League Schedule', description='This calendar contains practice and game times', time_zone='America/Los_Angeles', hidden=False, location='Oakland', color='#2952A3'): """Creates a new calendar using the specified data.""" print 'Creating new calendar with title "%s"' % title calendar = gdata.calendar.CalendarListEntry() calendar.title = atom.Title(text=title) calendar.summary = atom.Summary(text=description) calendar.where = gdata.calendar.Where(value_string=location) calendar.color = gdata.calendar.Color(value=color) calendar.timezone = gdata.calendar.Timezone(value=time_zone) if hidden: calendar.hidden = gdata.calendar.Hidden(value='true') else: calendar.hidden = gdata.calendar.Hidden(value='false') new_calendar = self.cal_client.InsertCalendar(new_calendar=calendar) return new_calendar
def uploadPhoto(self, file, description=""): ms = gdata.MediaSource() try: ms.setFile(file, 'image/jpeg') metadata_entry = gdata.GDataEntry() name = os.path.basename(file) metadata_entry.title = atom.Title(text=name) metadata_entry.summary = atom.Summary(text=description) metadata_entry.category.append( atom.Category( scheme='http://schemas.google.com/g/2005#kind', term='http://schemas.google.com/photos/2007#photo')) link = self.__ae.link[ 0].href # self.__ae.GetFeedLink().href on created album media_entry = self.__gd.Post(metadata_entry, link, media_source=ms) return True except gdata.service.RequestError: return False
def copy2google(pair, gd_client): album_g = strip_album_name(pair.album) try: gd_client.GetFeed('/data/feed/api/user/default/album/' + album_g) except gdata.photos.service.GooglePhotosException as GPE: if GPE.body == 'No album found.': gd_client.InsertAlbum(title=pair.album, summary='') else: raise album_url = '/data/feed/api/user/default/album/' + album_g local_full_path = os.path.join(pair.local_path, pair.local_fn) mimetype = mimetypes.guess_type(local_full_path, strict=True)[0] photoentry = gdata.photos.PhotoEntry() photoentry.title = atom.Title(text=pair.local_fn) photoentry.summary = atom.Summary(text='', summary_type='text') photo = gd_client.InsertPhoto(album_url, photoentry, local_full_path, mimetype) return photo
def post(self): calendar_link = "" if (settings.APP['gcalenabled']): ck = db.Key(self.request.get('clientkey')) ck_query = Clients.all() ck_query.filter('__key__ =', ck) client = ck_query.fetch(1) clientname = client[0].business try: cal_title = self.request.get('pname') + " - " + clientname projectdesc = 'Client: ' + clientname + ' ' projectdesc += 'Project: ' + self.request.get('pname') gconnect = Gconnection() gd_client = gconnect.calendar_connect() calendar = gdata.calendar.CalendarListEntry() calendar.title = atom.Title(text=cal_title) calendar.summary = atom.Summary(text=projectdesc) calendar.where = gdata.calendar.Where( value_string=settings.COMPANY["city"]) calendar.color = gdata.calendar.Color(value='#2952A3') calendar.timezone = gdata.calendar.Timezone( value='America/Los_Angeles') calendar.hidden = gdata.calendar.Hidden(value='false') new_calendar = gd_client.InsertCalendar(new_calendar=calendar) calendar_link = new_calendar.link[0].href except: # TODO figure out proper action to take calendar_link = "Something went wrong." projects = Projects() projects.client = db.Key(self.request.get('clientkey')) projects.pname = self.request.get('pname') projects.calendarid = calendar_link projects.status = 'empty' projects.summary = 0 projects.put() action = '/projects?clientkey=' + self.request.get('clientkey') + '' self.redirect(action)
def uploadPhoto(self, file, filename, md5, album): photoTitle = self.transformFilename2PhotoTitle(filename) tags = self.transformPhotoTitle2Tags(photoTitle) entry = gdata.photos.PhotoEntry() entry.title = atom.Title(text=photoTitle) entry.summary = atom.Summary(text=photoTitle, summary_type='text') entry.checksum = gdata.photos.Checksum(text=md5) entry.media.keywords = gdata.media.Keywords() entry.media.keywords.text = tags if (self.verbose): print '%s [%s]' % (filename, photoTitle) uploaded = False while uploaded == False: try: self.gdClient.InsertPhoto( '/data/feed/api/user/default/albumid/%s' % (album.gphoto_id.text), entry, file, content_type='image/jpeg') uploaded = True except gdata.photos.service.GooglePhotosException as e: print "Upload failed. ", e self.connect() time.sleep(2)
def upload_photo(gd_client, localPath, album, fileName): print 'Uploading: %s in Picasa Album: %s' % (os.path.basename(localPath), album.title.text) contentType = get_content_type(fileName) picasa_photo = gdata.photos.PhotoEntry() picasa_photo.title = atom.Title(text=fileName) picasa_photo.summary = atom.Summary(text='', summary_type='text') delay = 1 while True: try: gd_client.InsertPhoto(album, picasa_photo, localPath, content_type=contentType) break except gdata.photos.service.GooglePhotosException as e: # retry on upload failure print("Got exception " + str(e)) print("retrying in " + str(delay) + " seconds") time.sleep(delay) if delay <= 8: delay = delay * 2 else: print 'Upload failed, check solution and try later' break
def setUp(self): self.summary = atom.Summary()
def save(self): gcal = self.gCalendar if gcal: # existing calendar update new = False else: new = True gcal = gdata.calendar.CalendarListEntry() gcal.title = atom.Title(text=self.title) gcal.summary = atom.Summary(text=self.summary) if self.where: gcal.where = gdata.calendar.Where(value_string=self.where) elif gcal.where and gcal.where.text: self.where = gcal.where.text if self.color: gcal.color = gdata.calendar.Color(value=self.color) elif gcal.color and gcal.color.value: self.color = gcal.color.value if self.timezone: gcal.timezone = gdata.calendar.Timezone(value=self.timezone) elif gcal.timezone and gcal.timezone.value: self.timezone = gcal.timezone.value if new: new_gcal = with_request_error_try( lambda: self.account.service.InsertCalendar(new_calendar=gcal)) # gooogle replaces the title with the (email address) style Calendar Id #self.calendar_id = new_gcal.title.text new_gcal.title = atom.Title(text=self.title) new_gcal = self.account.service.UpdateCalendar(calendar=new_gcal) self.uri = new_gcal.id.text for link in new_gcal.link: if link.rel == 'alternate': self.feed_uri = link.href break else: new_gcal = with_request_error_try( lambda: self.account.service.UpdateCalendar(calendar=gcal)) m = re_cal_id.match(self.uri) if m: self.calendar_id = unquote(m.group(1)) # ACL model rule = self.getAclRule('default') if not self.default_share: # Not sharing if rule is not None: # remove the rule with_request_error_try(lambda: self.account.service. DeleteAclEntry(rule.GetEditLink().href)) else: if rule is None: # new rule self.setAclRule(role=self.default_share, scope_type='default') elif to_role_uri(self.default_share) != rule.role.value: # role change self.setAclRule(rule=rule, role=self.default_share) super(Calendar, self).save()