def _save_keyring(self, keyring_dict): """Helper to actually write the keyring to Google""" import gdata result = self.OK file_contents = base64.urlsafe_b64encode(pickle.dumps(keyring_dict)) try: if self.docs_entry: extra_headers = {'Content-Type': 'text/plain', 'Content-Length': len(file_contents)} self.docs_entry = self.client.Put( file_contents, self.docs_entry.GetEditMediaLink().href, extra_headers=extra_headers ) else: from gdata.docs.service import DocumentQuery # check for existence of folder, create if required folder_query = DocumentQuery(categories=['folder']) folder_query['title'] = self.collection folder_query['title-exact'] = 'true' docs = self.client.QueryDocumentListFeed(folder_query.ToUri()) if docs.entry: folder_entry = docs.entry[0] else: folder_entry = self.client.CreateFolder(self.collection) file_handle = io.BytesIO(file_contents) media_source = gdata.MediaSource( file_handle=file_handle, content_type='text/plain', content_length=len(file_contents), file_name='temp') self.docs_entry = self.client.Upload( media_source, self._get_doc_title(), folder_or_uri=folder_entry ) except gdata.service.RequestError as ex: try: if ex.message['reason'].lower().find('conflict') != -1: result = self.CONFLICT else: # Google docs has a bug when updating a shared document # using PUT from any account other that the owner. # It returns an error 400 "Sorry, there was an error saving # the file. Please try again" # *despite* actually updating the document! # Workaround by re-reading to see if it actually updated msg = 'Sorry, there was an error saving the file' if ex.message['body'].find(msg) != -1: new_docs_entry, new_keyring_dict = self._read() if new_keyring_dict == keyring_dict: result = self.OK else: result = self.FAIL else: result = self.FAIL except Exception: result = self.FAIL return result
def _read(self): from gdata.docs.service import DocumentQuery title_query = DocumentQuery(categories=[self.collection]) title_query['title'] = self._get_doc_title() title_query['title-exact'] = 'true' docs = self.client.QueryDocumentListFeed(title_query.ToUri()) if not docs.entry: if self.can_create: docs_entry = None keyring_dict = {} else: raise errors.InitError( '%s not found in %s and create not permitted' % (self._get_doc_title(), self.collection) ) else: docs_entry = docs.entry[0] file_contents = '' try: url = docs_entry.content.src url += '&exportFormat=txt' server_response = self.client.request('GET', url) if server_response.status != 200: raise errors.InitError( 'Could not read existing Google Docs keyring' ) file_contents = server_response.read() if file_contents.startswith(codecs.BOM_UTF8): file_contents = file_contents[len(codecs.BOM_UTF8) :] keyring_dict = pickle.loads( base64.urlsafe_b64decode(file_contents.decode('string-escape')) ) except pickle.UnpicklingError as ex: raise errors.InitError( 'Could not unpickle existing Google Docs keyring', ex ) except TypeError as ex: raise errors.InitError( 'Could not decode existing Google Docs keyring', ex ) return docs_entry, keyring_dict