temp escaping variables for gdrive upload
[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 import mimetypes
7 import os
8
9 import httplib2
10 from apiclient.discovery import build
11 from apiclient.http import MediaFileUpload
12 from oauth2client.client import flow_from_clientsecrets
13
14 from karmaworld.apps.notes.models import DriveAuth, Note
15
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'}
20
21 def build_flow():
22     """ Create an oauth2 autentication object with our preferred details """
23     scopes = [
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',
28     ]
29
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
35     return flow
36
37
38 def authorize():
39     """ Use an oauth2client flow object to generate the web url to create a new
40         auth that can be then stored """
41     flow = build_flow()
42     print flow.step1_get_authorize_url()
43
44
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 """
50     flow = build_flow()
51     creds = flow.step2_exchange(code)
52     return creds
53
54
55 def build_api_service(creds):
56     http = httplib2.Http()
57     http = creds.authorize(http)
58     return build('drive', 'v2', http=http), http
59
60
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
67     """
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)
73         creds.refresh(http)
74         auth.credentials = creds.to_json()
75         auth.save()
76     return creds, auth
77
78
79 def convert_with_google_drive(note):
80     """ Upload a local note and download HTML
81         using Google Drive
82         :note: a File model instance # FIXME
83     """
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)
87
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
92
93     fileName, fileExtension = os.path.splitext(note.file.path)
94
95     if file_type == None:
96
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
100         # file, return error
101         else:
102             raise Exception('Unknown file type')
103
104     resource = {
105                 'title':    note.title,
106                 'desc':     note.description,
107                 'mimeType': file_type
108             }
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)
113
114     auth = DriveAuth.objects.filter(email=GOOGLE_USER).all()[0]
115     creds = auth.transform_to_cred()
116
117
118     creds, auth = check_and_refresh(creds, auth)
119
120     service, http = build_api_service(creds)
121
122     # Upload the file
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()
126
127     # set note.is_pdf
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']
135     else:
136         # get the converted filetype urls
137         download_urls = {}
138         download_urls['html'] = file_dict[u'exportLinks']['text/html']
139         download_urls['text'] = file_dict[u'exportLinks']['text/plain']
140         content_dict = {}
141
142
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")
146
147
148             if resp.status in [200]:
149                 print "\t downloaded!"
150                 # save to the File.property resulting field
151                 content_dict[download_type] = content
152             else:
153                 print "\t Download failed: %s" % resp.status
154
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)
157
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']
162
163     # Finally, save whatever data we got back from google
164     new_file.save()