more tests for gdrive
[oweals/karmaworld.git] / karmaworld / apps / notes / gdrive.py
1 #!/usr/bin/env python
2 # -*- coding:utf8 -*-
3 # Copyright (C) 2012  FinalsClub Foundation
4
5 import datetime
6 from io import FileIO, BufferedWriter
7 import mimetypes
8 import os
9 import time
10
11 import httplib2
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
17
18 from karmaworld.apps.notes.models import DriveAuth, Note
19
20 CLIENT_SECRET = os.path.join(settings.DJANGO_ROOT, \
21                     'secret/client_secrets.json')
22 #from credentials import GOOGLE_USER # FIXME
23 try:
24     from secrets.drive import GOOGLE_USER
25 except:
26     GOOGLE_USER = 'admin@karmanotes.org' # FIXME
27
28 EXT_TO_MIME = {'.docx': 'application/msword'}
29
30 def build_flow():
31     """ Create an oauth2 autentication object with our preferred details """
32     scopes = [
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',
37     ]
38
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
44     return flow
45
46
47 def authorize():
48     """ Use an oauth2client flow object to generate the web url to create a new
49         auth that can be then stored """
50     flow = build_flow()
51     print flow.step1_get_authorize_url()
52
53
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 """
59     flow = build_flow()
60     creds = flow.step2_exchange(code)
61     return creds
62
63
64 def build_api_service(creds):
65     http = httplib2.Http()
66     http = creds.authorize(http)
67     return build('drive', 'v2', http=http), http
68
69
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
76     """
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)
82         creds.refresh(http)
83         auth.credentials = creds.to_json()
84         auth.save()
85     return creds, auth
86
87
88 def convert_with_google_drive(note):
89     """ Upload a local note and download HTML
90         using Google Drive
91         :note: a File model instance # FIXME
92     """
93     # TODO: set the permission of the file to permissive so we can use the
94     #       gdrive_url to serve files directly to users
95
96     # Get file_type and encoding of uploaded file
97     # i.e: file_type = 'text/plain', encoding = None
98     (file_type, encoding) = mimetypes.guess_type(note.note_file.path)
99
100     resource = {
101                 'title':    note.name,
102             }
103
104
105     if file_type != None:
106         media = MediaFileUpload(note.note_file.path, mimetype=file_type,
107                     chunksize=1024*1024, resumable=True)
108
109     else:
110         media = MediaFileUpload(note.note_file.path,
111                     chunksize=1024*1024, resumable=True)
112
113     auth = DriveAuth.objects.filter(email=GOOGLE_USER).all()[0]
114     creds = auth.transform_to_cred()
115
116
117     creds, auth = check_and_refresh(creds, auth)
118
119     service, http = build_api_service(creds)
120
121     # get the file extension
122     filename, extension = os.path.splitext(note.note_file.path)
123     # Upload the file
124     if extension.lower() in ['.pdf', '.jpeg', '.jpg', '.png']:
125         # include OCR on ocr-able files
126         file_dict = service.files().insert(body=resource, media_body=media, convert=True, ocr=True).execute()
127
128     else:
129         file_dict = service.files().insert(body=resource, media_body=media, convert=True).execute()
130
131     if u'exportLinks' not in file_dict:
132         # wait some seconds
133         # get the doc from gdrive
134         time.sleep(30)
135         file_dict = service.files().get(fileId=file_dict[u'id']).execute()
136
137     # get the converted filetype urls
138     download_urls = {}
139     download_urls['html'] = file_dict[u'exportLinks']['text/html']
140     download_urls['text'] = file_dict[u'exportLinks']['text/plain']
141     if extension.lower() in ['.ppt', 'pptx']:
142
143         download_urls['pdf'] = file_dict[u'exportLinks']['application/pdf']
144
145
146     content_dict = {}
147     for download_type, download_url in download_urls.items():
148         print "\n%s -- %s" % (download_type, download_urls)
149         resp, content = http.request(download_url, "GET")
150
151
152         if resp.status in [200]:
153             print "\t downloaded!"
154             # save to the File.property resulting field
155             content_dict[download_type] = content
156         else:
157             print "\t Download failed: %s" % resp.status
158
159     # Get a new copy of the file from the database with the new metadata from filemeta
160     new_note = Note.objects.get(id=note.id)
161     if extension.lower() == '.pdf':
162         new_note.file_type = 'pdf'
163
164     elif extension.lower() in ['.ppt', '.pptx']:
165         print "try to save ppt"
166         now = datetime.datetime.utcnow()
167         # create a folder path to store the ppt > pdf file with year and month folders
168         _path = os.path.join(settings.MEDIA_ROOT, 'ppt_pdf/%s/%s' % (now.year, now.month), filename)
169         try:
170             # If those folders don't exist, create them
171             os.makedirs(os.path.realpath(os.path.dirname(_path)))
172
173         _writer = BufferedWriter(FileIO(_path, "w"))
174         _writer.write(content_dict['pdf'])
175         _writer.close()
176
177
178         new_note.pdf_file = os.path.join(_path, filename)
179
180     # set the .odt as the download from google link
181     new_note.gdrive_url = file_dict[u'exportLinks']['application/vnd.oasis.opendocument.text']
182     new_note.html = content_dict['html']
183     new_note.text = content_dict['text']
184
185     # before we save new html, sanitize a tags in note.html
186     new_note.sanitize_html(save=False)
187
188     # Finally, save whatever data we got back from google
189     new_note.save()