diff --git a/base/models.py b/base/models.py index 71a8362390..c82197f8cf 100644 --- a/base/models.py +++ b/base/models.py @@ -1,3 +1,11 @@ from django.db import models -# Create your models here. + +class UuidOjbidMap(models.Model): + """ + Model used for store crocdoc uuid and file object id mapping. + """ + uuid = models.CharField(max_length=40) + obj_id = models.CharField(max_length=40, unique=True) + + diff --git a/settings.py b/settings.py index 461686e9bc..84bdd88307 100644 --- a/settings.py +++ b/settings.py @@ -205,6 +205,9 @@ SEAHUB_TITLE = 'SeaHub' USE_SUBDOMAIN = False ACCOUNT_TYPE = 'personal' +# Replace this with your Crocodoc.com api token +CROCODOC_API_TOKEN = '' + try: import local_settings except ImportError: diff --git a/templates/repo_file_get.html b/templates/repo_file_get.html index 0beeead7ff..9fe9b4437c 100644 --- a/templates/repo_file_get.html +++ b/templates/repo_file_get.html @@ -1,4 +1,4 @@ - if (filetype == 'Document') { + if (filetype == 'Text') { $.ajax({ url: url, dataType: 'json', @@ -18,6 +18,82 @@ $('#file-view').html('{{ u_filename}}').css({'text-align':'center', 'padding':'30px 0'}); } else if (filetype == 'SVG') { $('#file-view').html(''); - } else { + } else if (filetype == 'Document' ) { + var tid= 0; + var uuid = ''; + var obj_id = ''; + function create_session() { + $.ajax({ + url: '{{ SITE_ROOT }}crocodoc/session/?uuid=' + uuid, + dataType: 'json', + cache: false, + contentType: 'application/json; charset=utf-8', + success: function(data) { + if (data.length > 0) { + var doc_src = data[0]['doc_src']; + var iframe_src = '' + $('#file-view').html(iframe_src); + } + }, + error: function(xhr, ajaxOptions, thrownError) { + var jsonVal = jQuery.parseJSON(xhr.responseText); + $('#file-view').html('

' + jsonVal[0]['error'] + '

'); + } + }); + } + function abortTimer () { + clearTimeout(tid); + } + function check_status () { + $.ajax({ + url: '{{ SITE_ROOT }}crocodoc/status/?uuids='+ uuid + '&obj_id=' + obj_id, + dataType: 'json', + cache: false, + contentType: 'application/json; charset=utf-8', + success: function(data) { + if (data.length > 0) { + var status = data[0]['status'] + if (status == 'QUEUED') { + $('#file-view').html('

' + '文档转换任务正在排队,请稍后...' + '

'); + tid = setTimeout(check_status, 1000); } else if (status == 'PROCESSING') { + $('#file-view').html('

' + '文档正在转换,请稍候...' + '

'); + tid = setTimeout(check_status, 1000); } else if (status == 'DONE') { + $('#file-view').html('

' + '文档转换成功。正在打开...' + '

'); + abortTimer(); + create_session(); + } else { + abortTimer(); + } + } + }, + error: function(xhr, ajaxOptions, thrownError) { + var jsonVal = jQuery.parseJSON(xhr.responseText); + $('#file-view').html('

' + jsonVal[0]['error'] + '

'); + abortTimer(); + return false; + } + }); + } + $.ajax({ + url: '{{ SITE_ROOT }}crocodoc/upload/?raw_path={{ raw_path|urlencode }}', + dataType: 'json', + cache: false, + contentType: 'application/json; charset=utf-8', + success: function(data) { + if (data.length > 0) { + uuid = data[0]['uuid']; + obj_id = data[0]['obj_id']; + $('#file-view').html('

文档内容读取成功,开始转换...

'); + + tid = setTimeout(check_status, 1000); + } + }, + error: function(xhr, ajaxOptions, thrownError) { + var jsonVal = jQuery.parseJSON(xhr.responseText); + $('#file-view').html('

' + jsonVal[0]['error'] + '

'); + } + }); + } + else { $('#file-view').html('

该类型文件无法在线查看。下载

'); } \ No newline at end of file diff --git a/urls.py b/urls.py index fad5896dce..c83725dc14 100644 --- a/urls.py +++ b/urls.py @@ -13,7 +13,8 @@ from seahub.views import root, peers, myhome, \ repo_upload_file, file_upload_progress, file_upload_progress_page, \ get_subdir, file_move, repo_new_dir, repo_rename_file, validate_filename, \ repo_create, repo_update_file, file_revisions, \ - get_shared_link, view_shared_file, remove_shared_link, send_shared_link + get_shared_link, view_shared_file, remove_shared_link, send_shared_link, \ + crocodoc_upload, crocodoc_status, crocodoc_session from seahub.notifications.views import notification_list from seahub.share.views import share_admin from seahub.group.views import group_list @@ -68,7 +69,7 @@ urlpatterns = patterns('', url(r'^repo/(?P[^/]+)/files/$', repo_view_file, name="repo_view_file"), (r'^repo/(?P[^/]+)/file/get/$', repo_file_get), url(r'^repo/(?P[^/]+)/(?P[^/]+)/$', repo_access_file, name='repo_access_file'), - + (r'^download/repo/$', repo_download), (r'^file/move/get_subdir/$', get_subdir), (r'^file/move/$', file_move), @@ -81,6 +82,11 @@ urlpatterns = patterns('', (r'^useradmin/remove/(?P[^/]+)/$', user_remove), (r'^useradmin/info/(?P[^/]+)/$', user_info), (r'^useradmin/activate/(?P[^/]+)/$', activate_user), + + ### Document previewd ### + (r'^crocodoc/upload/$', crocodoc_upload), + (r'^crocodoc/status/$', crocodoc_status), + (r'^crocodoc/session/$', crocodoc_session), ### Apps ### (r'^avatar/', include('avatar.urls')), diff --git a/utils.py b/utils.py index 0234ac1d8e..2a09b1df6e 100644 --- a/utils.py +++ b/utils.py @@ -19,9 +19,10 @@ import settings EMPTY_SHA1 = '0000000000000000000000000000000000000000' PREVIEW_FILEEXT = { - 'Document': ('ac', 'am', 'bat', 'c', 'cc', 'cmake', 'cpp', 'css', 'diff', 'h', 'html', 'java', 'js', 'json', 'less', 'make', 'markdown', 'org', 'php', 'properties', 'py', 'rb', 'scala', 'script', 'sh', 'sql', 'txt','text', 'vi', 'vim'), + 'Text': ('ac', 'am', 'bat', 'c', 'cc', 'cmake', 'cpp', 'css', 'diff', 'h', 'html', 'java', 'js', 'json', 'less', 'make', 'markdown', 'org', 'php', 'properties', 'py', 'rb', 'scala', 'script', 'sh', 'sql', 'txt','text', 'vi', 'vim'), 'Image': ('gif', 'jpeg', 'jpg', 'png'), 'SVG': ('svg',), + 'Document': ('doc', 'docx', 'ppt', 'pptx'), } def go_permission_error(request, msg=None): diff --git a/views.py b/views.py index 8087dcf19b..a5b9df0d6c 100644 --- a/views.py +++ b/views.py @@ -5,6 +5,7 @@ import stat import simplejson as json import re import sys +import urllib import urllib2 from urllib import quote from django.core.urlresolvers import reverse @@ -33,6 +34,7 @@ from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_groups, get_users, get_re from pysearpc import SearpcError from seahub.base.accounts import CcnetUser +from seahub.base.models import UuidOjbidMap from seahub.contacts.models import Contact from seahub.notifications.models import UserNotification from forms import AddUserForm, FileLinkShareForm @@ -40,9 +42,10 @@ from utils import go_permission_error, go_error, list_to_string, \ get_httpserver_root, get_ccnetapplet_root, gen_token, \ calculate_repo_last_modify, valid_previewed_file, \ check_filename_with_rename, get_accessible_repos, EMPTY_SHA1, \ - get_file_revision_id_size, get_ccnet_server_addr_port, gen_file_get_url + get_file_revision_id_size, get_ccnet_server_addr_port, \ + gen_file_get_url from seahub.profile.models import Profile -from settings import FILE_PREVIEW_MAX_SIZE +from seahub.settings import FILE_PREVIEW_MAX_SIZE, CROCODOC_API_TOKEN @login_required def root(request): @@ -846,7 +849,7 @@ def repo_view_file(request, repo_id): # determin whether file can preview on web filetype = valid_previewed_file(filename) - + # raw path raw_path = gen_file_get_url(token, filename) @@ -881,6 +884,7 @@ def repo_view_file(request, repo_id): 'protocol': http_or_https, 'domain': domain, 'file_shared_link': file_shared_link, + # 'doc_src': doc_src, }, context_instance=RequestContext(request)) def repo_file_get(request, repo_id): @@ -1985,3 +1989,126 @@ def send_shared_link(request): msg = '发送成功。' data = json.dumps([{'msg': msg}]) return HttpResponse(data, status=200, content_type=content_type) + +def crocodoc_upload(request): + """ + Handle ajax request to upload document to crocodoc.com. + """ + if not request.is_ajax(): + raise Http404 + + content_type = 'application/json; charset=utf-8' + raw_path = request.GET.get('raw_path', '') + + # Fetch obj_id according token, if this obj_id already has uuid, + # send uuid; else, upload file. + obj_id = seafserv_rpc.web_query_access_token(raw_path.split('/files/')[1][:5]).obj_id + if not obj_id: + # Should nerver reach here. + data = json.dumps([{'error': '缺少obj_id'}]) + return HttpResponse(data, status=500, content_type=content_type) + try: + uo = UuidOjbidMap.objects.get(obj_id=obj_id) + except UuidOjbidMap.DoesNotExist: + uo = None + if uo: + data = json.dumps([{'uuid': uo.uuid, 'obj_id': obj_id}]) + return HttpResponse(data, status=200, content_type=content_type) + + curl = "https://crocodoc.com/api/v2/document/upload" + data = {'token': CROCODOC_API_TOKEN, + 'url': raw_path} + try: + f = urllib2.urlopen(url=curl, data=urllib.urlencode(data)) + except urllib2.URLError, e: + data = json.dumps([{'error': e.msg}]) + return HttpResponse(data, status=500, content_type=content_type) + else: + ret = f.read() + ret_dict = json.loads(ret) + if ret_dict.has_key('error'): + data = json.dumps([{'error': ret_dict['error']}]) + return HttpResponse(data, status=500, content_type=content_type) + else: + data = json.dumps([{'uuid': ret_dict['uuid'], 'obj_id': obj_id}]) + return HttpResponse(data, status=200, content_type=content_type) + +def crocodoc_status(request): + """ + Handle ajax request to get status of the document from crocodoc.com. + """ + if not request.is_ajax(): + raise Http404 + + content_type = 'application/json; charset=utf-8' + uuids = request.GET.get('uuids', '') + obj_id = request.GET.get('obj_id', '') + + curl = 'https://crocodoc.com/api/v2/document/status?token=%s&uuids=%s' % ( + CROCODOC_API_TOKEN, uuids + ) + + f = urllib2.urlopen(url=curl) + ret = f.read() + ret_list = json.loads(ret) + ret_dict = ret_list[0] + if ret_dict.has_key('error'): + # Delete obj_id-uuid in db + UuidOjbidMap.objects.filter(obj_id=obj_id).delete() + + data = json.dumps([{'error': '文档转换出错:' + ret_dict['error']}]) + return HttpResponse(data, status=500, content_type=content_type) + + viewable = ret_dict['viewable'] # TODO: this may used in large file preview + status = ret_dict['status'] + if status == 'QUEUED': + data = json.dumps([{'status': status}]) + return HttpResponse(data, status=200, content_type=content_type) + elif status == 'PROCESSING': + data = json.dumps([{'status': status}]) + return HttpResponse(data, status=200, content_type=content_type) + elif status == 'DONE': + # Cache obj_id and uuid in db + uo = UuidOjbidMap(uuid=uuids, obj_id=obj_id) + try: + uo.save() + except IntegrityError, e: + pass + + data = json.dumps([{'status': status}]) + return HttpResponse(data, status=200, content_type=content_type) + elif status == 'ERROR': + # Delete obj_id-uuid in db + UuidOjbidMap.objects.filter(obj_id=obj_id).delete() + + err_msg = '文档转换出错:' + ret_dict['error'] if ret_dict.has_key('error') \ + else '文档转换出错' + data = json.dumps([{'error': err_msg}]) + return HttpResponse(data, status=500, content_type=content_type) + +def crocodoc_session(request): + """ + Handle ajax reqeust to create session. + Session expires 60 minutes after it's generated. + """ + if not request.is_ajax(): + raise Http404 + + content_type = 'application/json; charset=utf-8' + uuid = request.GET.get('uuid', '') + + curl = 'https://crocodoc.com/api/v2/session/create' + data = {'token': CROCODOC_API_TOKEN, + 'uuid': uuid, + 'editable': 'true', + 'user': '1337,Peter', # TODO: Fake user, should be changed + 'downloadable': 'true', + } + f = urllib2.urlopen(url=curl, data=urllib.urlencode(data)) + ret = f.read() + ret_dict = json.loads(ret) + session = ret_dict['session'] + doc_src = 'https://crocodoc.com/view/%s' % session + + data = json.dumps([{'doc_src': doc_src}]) + return HttpResponse(data, status=200, content_type=content_type)