| #!/usr/bin/python |
| # |
| # Copyright (C) 2007, 2009 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. |
| |
| |
| __author__ = ('api.jfisher (Jeff Fisher), ' |
| 'e.bidelman (Eric Bidelman)') |
| |
| |
| import sys |
| import re |
| import os.path |
| import getopt |
| import getpass |
| import gdata.docs.service |
| import gdata.spreadsheet.service |
| |
| |
| def truncate(content, length=15, suffix='...'): |
| if len(content) <= length: |
| return content |
| else: |
| return content[:length] + suffix |
| |
| |
| class DocsSample(object): |
| """A DocsSample object demonstrates the Document List feed.""" |
| |
| def __init__(self, email, password): |
| """Constructor for the DocsSample object. |
| |
| Takes an email and password corresponding to a gmail account to |
| demonstrate the functionality of the Document List feed. |
| |
| Args: |
| email: [string] The e-mail address of the account to use for the sample. |
| password: [string] The password corresponding to the account specified by |
| the email parameter. |
| |
| Returns: |
| A DocsSample object used to run the sample demonstrating the |
| functionality of the Document List feed. |
| """ |
| source = 'Document List Python Sample' |
| self.gd_client = gdata.docs.service.DocsService() |
| self.gd_client.ClientLogin(email, password, source=source) |
| |
| # Setup a spreadsheets service for downloading spreadsheets |
| self.gs_client = gdata.spreadsheet.service.SpreadsheetsService() |
| self.gs_client.ClientLogin(email, password, source=source) |
| |
| def _PrintFeed(self, feed): |
| """Prints out the contents of a feed to the console. |
| |
| Args: |
| feed: A gdata.docs.DocumentListFeed instance. |
| """ |
| print '\n' |
| if not feed.entry: |
| print 'No entries in feed.\n' |
| print '%-18s %-12s %s' % ('TITLE', 'TYPE', 'RESOURCE ID') |
| for entry in feed.entry: |
| print '%-18s %-12s %s' % (truncate(entry.title.text.encode('UTF-8')), |
| entry.GetDocumentType(), |
| entry.resourceId.text) |
| |
| def _GetFileExtension(self, file_name): |
| """Returns the uppercase file extension for a file. |
| |
| Args: |
| file_name: [string] The basename of a filename. |
| |
| Returns: |
| A string containing the file extension of the file. |
| """ |
| match = re.search('.*\.([a-zA-Z]{3,}$)', file_name) |
| if match: |
| return match.group(1).upper() |
| return False |
| |
| def _UploadMenu(self): |
| """Prompts that enable a user to upload a file to the Document List feed.""" |
| file_path = '' |
| file_path = raw_input('Enter path to file: ') |
| |
| if not file_path: |
| return |
| elif not os.path.isfile(file_path): |
| print 'Not a valid file.' |
| return |
| |
| file_name = os.path.basename(file_path) |
| ext = self._GetFileExtension(file_name) |
| |
| if not ext or ext not in gdata.docs.service.SUPPORTED_FILETYPES: |
| print 'File type not supported. Check the file extension.' |
| return |
| else: |
| content_type = gdata.docs.service.SUPPORTED_FILETYPES[ext] |
| |
| title = '' |
| while not title: |
| title = raw_input('Enter name for document: ') |
| |
| try: |
| ms = gdata.MediaSource(file_path=file_path, content_type=content_type) |
| except IOError: |
| print 'Problems reading file. Check permissions.' |
| return |
| |
| if ext in ['CSV', 'ODS', 'XLS', 'XLSX']: |
| print 'Uploading spreadsheet...' |
| elif ext in ['PPT', 'PPS']: |
| print 'Uploading presentation...' |
| else: |
| print 'Uploading word processor document...' |
| |
| entry = self.gd_client.Upload(ms, title) |
| |
| if entry: |
| print 'Upload successful!' |
| print 'Document now accessible at:', entry.GetAlternateLink().href |
| else: |
| print 'Upload error.' |
| |
| def _DownloadMenu(self): |
| """Prompts that enable a user to download a local copy of a document.""" |
| resource_id = '' |
| resource_id = raw_input('Enter an resource id: ') |
| file_path = '' |
| file_path = raw_input('Save file to: ') |
| |
| if not file_path or not resource_id: |
| return |
| |
| file_name = os.path.basename(file_path) |
| ext = self._GetFileExtension(file_name) |
| |
| if not ext or ext not in gdata.docs.service.SUPPORTED_FILETYPES: |
| print 'File type not supported. Check the file extension.' |
| return |
| else: |
| content_type = gdata.docs.service.SUPPORTED_FILETYPES[ext] |
| |
| doc_type = resource_id[:resource_id.find(':')] |
| |
| # When downloading a spreadsheet, the authenticated request needs to be |
| # sent with the spreadsheet service's auth token. |
| if doc_type == 'spreadsheet': |
| print 'Downloading spreadsheet to %s...' % (file_path,) |
| docs_token = self.gd_client.GetClientLoginToken() |
| self.gd_client.SetClientLoginToken(self.gs_client.GetClientLoginToken()) |
| self.gd_client.Export(resource_id, file_path, gid=0) |
| self.gd_client.SetClientLoginToken(docs_token) |
| else: |
| print 'Downloading document to %s...' % (file_path,) |
| self.gd_client.Export(resource_id, file_path) |
| |
| def _ListDocuments(self): |
| """Retrieves and displays a list of documents based on the user's choice.""" |
| print 'Retrieve (all/document/folder/presentation/spreadsheet/pdf): ' |
| category = raw_input('Enter a category: ') |
| |
| if category == 'all': |
| feed = self.gd_client.GetDocumentListFeed() |
| elif category == 'folder': |
| query = gdata.docs.service.DocumentQuery(categories=['folder'], |
| params={'showfolders': 'true'}) |
| feed = self.gd_client.Query(query.ToUri()) |
| else: |
| query = gdata.docs.service.DocumentQuery(categories=[category]) |
| feed = self.gd_client.Query(query.ToUri()) |
| |
| self._PrintFeed(feed) |
| |
| def _ListAclPermissions(self): |
| """Retrieves a list of a user's folders and displays them.""" |
| resource_id = raw_input('Enter an resource id: ') |
| query = gdata.docs.service.DocumentAclQuery(resource_id) |
| print '\nListing document permissions:' |
| feed = self.gd_client.GetDocumentListAclFeed(query.ToUri()) |
| for acl_entry in feed.entry: |
| print '%s - %s (%s)' % (acl_entry.role.value, acl_entry.scope.value, |
| acl_entry.scope.type) |
| |
| def _ModifyAclPermissions(self): |
| """Create or updates the ACL entry on an existing document.""" |
| resource_id = raw_input('Enter an resource id: ') |
| email = raw_input('Enter an email address: ') |
| role_value = raw_input('Enter a permission (reader/writer/owner/remove): ') |
| |
| uri = gdata.docs.service.DocumentAclQuery(resource_id).ToUri() |
| acl_feed = self.gd_client.GetDocumentListAclFeed(uri) |
| |
| found_acl_entry = None |
| for acl_entry in acl_feed.entry: |
| if acl_entry.scope.value == email: |
| found_acl_entry = acl_entry |
| break |
| |
| if found_acl_entry: |
| if role_value == 'remove': |
| # delete ACL entry |
| self.gd_client.Delete(found_acl_entry.GetEditLink().href) |
| else: |
| # update ACL entry |
| found_acl_entry.role.value = role_value |
| updated_entry = self.gd_client.Put( |
| found_acl_entry, found_acl_entry.GetEditLink().href, |
| converter=gdata.docs.DocumentListAclEntryFromString) |
| else: |
| scope = gdata.docs.Scope(value=email, type='user') |
| role = gdata.docs.Role(value=role_value) |
| acl_entry = gdata.docs.DocumentListAclEntry(scope=scope, role=role) |
| inserted_entry = self.gd_client.Post( |
| acl_entry, uri, converter=gdata.docs.DocumentListAclEntryFromString) |
| |
| print '\nListing document permissions:' |
| acl_feed = self.gd_client.GetDocumentListAclFeed(uri) |
| for acl_entry in acl_feed.entry: |
| print '%s - %s (%s)' % (acl_entry.role.value, acl_entry.scope.value, |
| acl_entry.scope.type) |
| |
| def _FullTextSearch(self): |
| """Searches a user's documents for a text string. |
| |
| Provides prompts to search a user's documents and displays the results |
| of such a search. The text_query parameter of the DocumentListQuery object |
| corresponds to the contents of the q parameter in the feed. Note that this |
| parameter searches the content of documents, not just their titles. |
| """ |
| input = raw_input('Enter search term: ') |
| query = gdata.docs.service.DocumentQuery(text_query=input) |
| feed = self.gd_client.Query(query.ToUri()) |
| self._PrintFeed(feed) |
| |
| def _PrintMenu(self): |
| """Displays a menu of options for the user to choose from.""" |
| print ('\nDocument List Sample\n' |
| '1) List your documents.\n' |
| '2) Search your documents.\n' |
| '3) Upload a document.\n' |
| '4) Download a document.\n' |
| "5) List a document's permissions.\n" |
| "6) Add/change a document's permissions.\n" |
| '7) Exit.\n') |
| |
| def _GetMenuChoice(self, max): |
| """Retrieves the menu selection from the user. |
| |
| Args: |
| max: [int] The maximum number of allowed choices (inclusive) |
| |
| Returns: |
| The integer of the menu item chosen by the user. |
| """ |
| while True: |
| input = raw_input('> ') |
| |
| try: |
| num = int(input) |
| except ValueError: |
| print 'Invalid choice. Please choose a value between 1 and', max |
| continue |
| |
| if num > max or num < 1: |
| print 'Invalid choice. Please choose a value between 1 and', max |
| else: |
| return num |
| |
| def Run(self): |
| """Prompts the user to choose funtionality to be demonstrated.""" |
| try: |
| while True: |
| self._PrintMenu() |
| choice = self._GetMenuChoice(7) |
| |
| if choice == 1: |
| self._ListDocuments() |
| elif choice == 2: |
| self._FullTextSearch() |
| elif choice == 3: |
| self._UploadMenu() |
| elif choice == 4: |
| self._DownloadMenu() |
| elif choice == 5: |
| self._ListAclPermissions() |
| elif choice == 6: |
| self._ModifyAclPermissions() |
| elif choice == 7: |
| print '\nGoodbye.' |
| return |
| except KeyboardInterrupt: |
| print '\nGoodbye.' |
| return |
| |
| |
| def main(): |
| """Demonstrates use of the Docs extension using the DocsSample object.""" |
| # Parse command line options |
| try: |
| opts, args = getopt.getopt(sys.argv[1:], '', ['user=', 'pw=']) |
| except getopt.error, msg: |
| print 'python docs_example.py --user [username] --pw [password] ' |
| sys.exit(2) |
| |
| user = '' |
| pw = '' |
| key = '' |
| # Process options |
| for option, arg in opts: |
| if option == '--user': |
| user = arg |
| elif option == '--pw': |
| pw = arg |
| |
| while not user: |
| print 'NOTE: Please run these tests only with a test account.' |
| user = raw_input('Please enter your username: ') |
| while not pw: |
| pw = getpass.getpass() |
| if not pw: |
| print 'Password cannot be blank.' |
| |
| try: |
| sample = DocsSample(user, pw) |
| except gdata.service.BadAuthentication: |
| print 'Invalid user credentials given.' |
| return |
| |
| sample.Run() |
| |
| |
| if __name__ == '__main__': |
| main() |