3 # Copyright (C) 2012 FinalsClub Foundation
6 from io import FileIO, BufferedWriter
12 from apiclient.discovery import build
13 from apiclient.http import MediaFileUpload
14 from django.conf import settings
15 from django.core.files import File
16 from oauth2client.client import flow_from_clientsecrets
18 from karmaworld.apps.notes.models import DriveAuth, Note
20 CLIENT_SECRET = os.path.join(settings.DJANGO_ROOT, \
21 'secret/client_secrets.json')
22 #from credentials import GOOGLE_USER # FIXME
24 from secrets.drive import GOOGLE_USER
26 GOOGLE_USER = 'admin@karmanotes.org' # FIXME
28 EXT_TO_MIME = {'.docx': 'application/msword'}
31 """ Create an oauth2 autentication object with our preferred details """
33 'https://www.googleapis.com/auth/drive',
34 'https://www.googleapis.com/auth/drive.file',
35 'https://www.googleapis.com/auth/userinfo.email',
36 'https://www.googleapis.com/auth/userinfo.profile',
39 flow = flow_from_clientsecrets(CLIENT_SECRET, ' '.join(scopes), \
40 redirect_uri='http://localhost:8000/oauth2callback')
41 flow.params['access_type'] = 'offline'
42 flow.params['approval_prompt'] = 'force'
43 flow.params['user_id'] = GOOGLE_USER
48 """ Use an oauth2client flow object to generate the web url to create a new
49 auth that can be then stored """
51 print flow.step1_get_authorize_url()
54 def accept_auth(code):
55 """ Callback endpoint for accepting the post `authorize()` google drive
56 response, and generate a credentials object
57 :code: An authentication token from a WEB oauth dialog
58 returns a oauth2client credentials object """
60 creds = flow.step2_exchange(code)
64 def build_api_service(creds):
65 http = httplib2.Http()
66 http = creds.authorize(http)
67 return build('drive', 'v2', http=http), http
70 def check_and_refresh(creds, auth):
71 """ Check a Credentials object's expiration token
72 if it is out of date, refresh the token and save
73 :creds: a Credentials object
74 :auth: a DriveAuth that backs the cred object
75 :returns: updated creds and auth objects
77 if creds.token_expiry < datetime.datetime.utcnow():
78 # if we are passed the token expiry,
79 # refresh the creds and store them
80 http = httplib2.Http()
81 http = creds.authorize(http)
83 auth.credentials = creds.to_json()
87 def download_from_gdrive(file_dict, http, extension):
88 """ get urls from file_dict and download contextual files from google """
90 download_urls['text'] = file_dict[u'exportLinks']['text/plain']
92 if extension.lower() in ['.ppt', 'pptx']:
93 download_urls['pdf'] = file_dict[u'exportLinks']['application/pdf']
95 download_urls['html'] = file_dict[u'exportLinks']['text/html']
99 for download_type, download_url in download_urls.items():
100 print "\n%s -- %s" % (download_type, download_urls)
101 resp, content = http.request(download_url, "GET")
103 if resp.status in [200]:
104 print "\t downloaded!"
105 # save to the File.property resulting field
106 content_dict[download_type] = content
108 print "\t Download failed: %s" % resp.status
112 def upload_to_gdrive(service, media, filename, extension):
113 """ take a gdrive service object, and a media wrapper and upload to gdrive
114 returns a file_dict """
115 _resource = {'title': filename}
116 if extension.lower() in ['.pdf', '.jpeg', '.jpg', '.png']:
117 # include OCR on ocr-able files
118 file_dict = service.files().insert(body=_resource, media_body=media, convert=True, ocr=True).execute()
121 file_dict = service.files().insert(body=_resource, media_body=media, convert=True).execute()
123 if u'exportLinks' not in file_dict:
125 # get the doc from gdrive
127 file_dict = service.files().get(fileId=file_dict[u'id']).execute()
131 def convert_with_google_drive(note):
132 """ Upload a local note and download HTML
134 :note: a File model instance # FIXME
136 # TODO: set the permission of the file to permissive so we can use the
137 # gdrive_url to serve files directly to users
139 # Get file_type and encoding of uploaded file
140 # i.e: file_type = 'text/plain', encoding = None
141 (file_type, encoding) = mimetypes.guess_type(note.note_file.path)
145 if file_type != None:
146 media = MediaFileUpload(note.note_file.path, mimetype=file_type,
147 chunksize=1024*1024, resumable=True)
150 media = MediaFileUpload(note.note_file.path,
151 chunksize=1024*1024, resumable=True)
153 auth = DriveAuth.objects.filter(email=GOOGLE_USER).all()[0]
154 creds = auth.transform_to_cred()
157 creds, auth = check_and_refresh(creds, auth)
159 service, http = build_api_service(creds)
161 # get the file extension
162 filename, extension = os.path.splitext(note.note_file.path)
164 file_dict = upload_to_gdrive(service, media, filename, extension)
166 content_dict = download_from_gdrive(file_dict, http, extension)
168 # Get a new copy of the file from the database with the new metadata from filemeta
169 new_note = Note.objects.get(id=note.id)
171 if extension.lower() == '.pdf':
172 new_note.file_type = 'pdf'
174 elif extension.lower() in ['.ppt', '.pptx']:
175 new_note.file_type = 'ppt'
176 now = datetime.datetime.utcnow()
177 # create a folder path to store the ppt > pdf file with year and month folders
178 nonce_path = '/ppt_pdf/%s/%s/' % (now.year, now.month)
180 _path = filename + '.pdf'
182 # If those folders don't exist, create them
183 os.makedirs(os.path.realpath(os.path.dirname(_path)))
185 print "we failed to create those directories"
187 _writer = BufferedWriter(FileIO(_path, "w"))
188 _writer.write(content_dict['pdf'])
191 new_note.pdf_file = _path
194 # PPT files do not have this export ability
195 new_note.gdrive_url = file_dict[u'exportLinks']['application/vnd.oasis.opendocument.text']
196 new_note.html = content_dict['html']
198 new_note.text = content_dict['text']
200 # before we save new html, sanitize a tags in note.html
201 #new_note.sanitize_html(save=False)
202 #FIXME: ^^^ disabled until we can get html out of an Etree html element
204 # Finally, save whatever data we got back from google