3 # Copyright (C) 2012 FinalsClub Foundation
10 from apiclient.discovery import build
11 from apiclient.http import MediaFileUpload
12 from oauth2client.client import flow_from_clientsecrets
14 from karmaworld.apps.notes.models import DriveAuth, Note
16 CLIENT_SECRET = './notes/client_secrets.json' # FIXME
17 #from credentials import GOOGLE_USER # FIXME
18 GOOGLE_USER = 'admin@karmanotes.org' # FIXME
19 EXT_TO_MIME = {'.docx': 'application/msword'}
22 """ Create an oauth2 autentication object with our preferred details """
24 'https://www.googleapis.com/auth/drive',
25 'https://www.googleapis.com/auth/drive.file',
26 'https://www.googleapis.com/auth/userinfo.email',
27 'https://www.googleapis.com/auth/userinfo.profile',
30 flow = flow_from_clientsecrets(CLIENT_SECRET, ' '.join(scopes), \
31 redirect_uri='http://localhost:8000/oauth2callback')
32 flow.params['access_type'] = 'offline'
33 flow.params['approval_prompt'] = 'force'
34 flow.params['user_id'] = GOOGLE_USER
39 """ Use an oauth2client flow object to generate the web url to create a new
40 auth that can be then stored """
42 print flow.step1_get_authorize_url()
45 def accept_auth(code):
46 """ Callback endpoint for accepting the post `authorize()` google drive
47 response, and generate a credentials object
48 :code: An authentication token from a WEB oauth dialog
49 returns a oauth2client credentials object """
51 creds = flow.step2_exchange(code)
55 def build_api_service(creds):
56 http = httplib2.Http()
57 http = creds.authorize(http)
58 return build('drive', 'v2', http=http), http
61 def check_and_refresh(creds, auth):
62 """ Check a Credentials object's expiration token
63 if it is out of date, refresh the token and save
64 :creds: a Credentials object
65 :auth: a DriveAuth that backs the cred object
66 :returns: updated creds and auth objects
68 if creds.token_expiry < datetime.datetime.utcnow():
69 # if we are passed the token expiry,
70 # refresh the creds and store them
71 http = httplib2.Http()
72 http = creds.authorize(http)
74 auth.credentials = creds.to_json()
79 def convert_with_google_drive(note):
80 """ Upload a local note and download HTML
82 :note: a File model instance # FIXME
84 # Get file_type and encoding of uploaded file
85 # i.e: file_type = 'text/plain', encoding = None
86 (file_type, encoding) = mimetypes.guess_type(note.file.path)
88 # If mimetype cannot be guessed
89 # Check against known issues, then
90 # finally, Raise Exception
91 # Extract file extension and compare it to EXT_TO_MIME dict
93 fileName, fileExtension = os.path.splitext(note.file.path)
97 if fileExtension.strip().lower() in EXT_TO_MIME:
98 file_type = EXT_TO_MIME[fileExtension.strip().lower()]
99 # If boy mimetypes.guess_type and EXT_TO_MIME fail to cover
102 raise Exception('Unknown file type')
106 'desc': note.description,
107 'mimeType': file_type
109 # TODO: set the permission of the file to permissive so we can use the
110 # gdrive_url to serve files directly to users
111 media = MediaFileUpload(note.file.path, mimetype=file_type,
112 chunksize=1024*1024, resumable=True)
114 auth = DriveAuth.objects.filter(email=GOOGLE_USER).all()[0]
115 creds = auth.transform_to_cred()
118 creds, auth = check_and_refresh(creds, auth)
120 service, http = build_api_service(creds)
123 # TODO: wrap this in a try loop that does a token refresh if it fails
124 print "Trying to upload document"
125 file_dict = service.files().insert(body=resource, media_body=media, convert=True).execute()
128 if file_type == 'application/pdf':
129 # Get a new copy of the file from the database with the new metadata from filemeta
130 new_file = File.objects.get(id=note.id)
131 # If it's a pdf, instead save an embed_url from resource['selfLink']
132 new_file.is_pdf = True
133 new_file.embed_url = file_dict[u'selfLink']
134 new_file.gdrive_url = file_dict[u'downloadUrl']
136 # get the converted filetype urls
138 download_urls['html'] = file_dict[u'exportLinks']['text/html']
139 download_urls['text'] = file_dict[u'exportLinks']['text/plain']
143 for download_type, download_url in download_urls.items():
144 print "\n%s -- %s" % (download_type, download_urls)
145 resp, content = http.request(download_url, "GET")
148 if resp.status in [200]:
149 print "\t downloaded!"
150 # save to the File.property resulting field
151 content_dict[download_type] = content
153 print "\t Download failed: %s" % resp.status
155 # Get a new copy of the file from the database with the new metadata from filemeta
156 new_file = Note.objects.get(id=note.id)
158 # set the .odt as the download from google link
159 new_file.gdrive_url = file_dict[u'exportLinks']['application/vnd.oasis.opendocument.text']
160 new_file.html = content_dict['html']
161 new_file.text = content_dict['text']
163 # Finally, save whatever data we got back from google