1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-04 08:28:11 +00:00

Add document preview feature

This commit is contained in:
xiez
2012-07-23 22:44:09 +08:00
parent 0306ff75b7
commit 4b2558a6c5
6 changed files with 230 additions and 9 deletions

View File

@@ -1,3 +1,11 @@
from django.db import models 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)

View File

@@ -205,6 +205,9 @@ SEAHUB_TITLE = 'SeaHub'
USE_SUBDOMAIN = False USE_SUBDOMAIN = False
ACCOUNT_TYPE = 'personal' ACCOUNT_TYPE = 'personal'
# Replace this with your Crocodoc.com api token
CROCODOC_API_TOKEN = ''
try: try:
import local_settings import local_settings
except ImportError: except ImportError:

View File

@@ -1,4 +1,4 @@
if (filetype == 'Document') { if (filetype == 'Text') {
$.ajax({ $.ajax({
url: url, url: url,
dataType: 'json', dataType: 'json',
@@ -18,6 +18,82 @@
$('#file-view').html('<img src="{{ raw_path }}" alt="{{ u_filename}}" id="image-view" />').css({'text-align':'center', 'padding':'30px 0'}); $('#file-view').html('<img src="{{ raw_path }}" alt="{{ u_filename}}" id="image-view" />').css({'text-align':'center', 'padding':'30px 0'});
} else if (filetype == 'SVG') { } else if (filetype == 'SVG') {
$('#file-view').html('<iframe src="{{ raw_path }}" frameborder="0" width="940" id="svg-view"></iframe>'); $('#file-view').html('<iframe src="{{ raw_path }}" frameborder="0" width="940" id="svg-view"></iframe>');
} 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 = '<iframe src="' + doc_src + '" frameborder="0" width="940" id="svg-view"></iframe>'
$('#file-view').html(iframe_src);
}
},
error: function(xhr, ajaxOptions, thrownError) {
var jsonVal = jQuery.parseJSON(xhr.responseText);
$('#file-view').html('<p class="error">' + jsonVal[0]['error'] + '</p>');
}
});
}
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('<p class="msg">' + '文档转换任务正在排队,请稍后...' + '</p>');
tid = setTimeout(check_status, 1000); } else if (status == 'PROCESSING') {
$('#file-view').html('<p class="msg">' + '文档正在转换,请稍候...' + '</p>');
tid = setTimeout(check_status, 1000); } else if (status == 'DONE') {
$('#file-view').html('<p class="msg">' + '文档转换成功。正在打开...' + '</p>');
abortTimer();
create_session();
} else {
abortTimer();
}
}
},
error: function(xhr, ajaxOptions, thrownError) {
var jsonVal = jQuery.parseJSON(xhr.responseText);
$('#file-view').html('<p class="error">' + jsonVal[0]['error'] + '</p>');
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('<p class="msg">文档内容读取成功,开始转换...</p>');
tid = setTimeout(check_status, 1000);
}
},
error: function(xhr, ajaxOptions, thrownError) {
var jsonVal = jQuery.parseJSON(xhr.responseText);
$('#file-view').html('<p class="error">' + jsonVal[0]['error'] + '</p>');
}
});
}
else {
$('#file-view').html('<p>该类型文件无法在线查看。<a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download">下载</a></p>'); $('#file-view').html('<p>该类型文件无法在线查看。<a href="{{ SITE_ROOT }}repo/{{ repo.id }}/{{ obj_id }}/?file_name={{ file_name }}&op=download">下载</a></p>');
} }

10
urls.py
View File

@@ -13,7 +13,8 @@ from seahub.views import root, peers, myhome, \
repo_upload_file, file_upload_progress, file_upload_progress_page, \ repo_upload_file, file_upload_progress, file_upload_progress_page, \
get_subdir, file_move, repo_new_dir, repo_rename_file, validate_filename, \ get_subdir, file_move, repo_new_dir, repo_rename_file, validate_filename, \
repo_create, repo_update_file, file_revisions, \ 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.notifications.views import notification_list
from seahub.share.views import share_admin from seahub.share.views import share_admin
from seahub.group.views import group_list from seahub.group.views import group_list
@@ -68,7 +69,7 @@ urlpatterns = patterns('',
url(r'^repo/(?P<repo_id>[^/]+)/files/$', repo_view_file, name="repo_view_file"), url(r'^repo/(?P<repo_id>[^/]+)/files/$', repo_view_file, name="repo_view_file"),
(r'^repo/(?P<repo_id>[^/]+)/file/get/$', repo_file_get), (r'^repo/(?P<repo_id>[^/]+)/file/get/$', repo_file_get),
url(r'^repo/(?P<repo_id>[^/]+)/(?P<obj_id>[^/]+)/$', repo_access_file, name='repo_access_file'), url(r'^repo/(?P<repo_id>[^/]+)/(?P<obj_id>[^/]+)/$', repo_access_file, name='repo_access_file'),
(r'^download/repo/$', repo_download), (r'^download/repo/$', repo_download),
(r'^file/move/get_subdir/$', get_subdir), (r'^file/move/get_subdir/$', get_subdir),
(r'^file/move/$', file_move), (r'^file/move/$', file_move),
@@ -81,6 +82,11 @@ urlpatterns = patterns('',
(r'^useradmin/remove/(?P<user_id>[^/]+)/$', user_remove), (r'^useradmin/remove/(?P<user_id>[^/]+)/$', user_remove),
(r'^useradmin/info/(?P<email>[^/]+)/$', user_info), (r'^useradmin/info/(?P<email>[^/]+)/$', user_info),
(r'^useradmin/activate/(?P<user_id>[^/]+)/$', activate_user), (r'^useradmin/activate/(?P<user_id>[^/]+)/$', activate_user),
### Document previewd ###
(r'^crocodoc/upload/$', crocodoc_upload),
(r'^crocodoc/status/$', crocodoc_status),
(r'^crocodoc/session/$', crocodoc_session),
### Apps ### ### Apps ###
(r'^avatar/', include('avatar.urls')), (r'^avatar/', include('avatar.urls')),

View File

@@ -19,9 +19,10 @@ import settings
EMPTY_SHA1 = '0000000000000000000000000000000000000000' EMPTY_SHA1 = '0000000000000000000000000000000000000000'
PREVIEW_FILEEXT = { 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'), 'Image': ('gif', 'jpeg', 'jpg', 'png'),
'SVG': ('svg',), 'SVG': ('svg',),
'Document': ('doc', 'docx', 'ppt', 'pptx'),
} }
def go_permission_error(request, msg=None): def go_permission_error(request, msg=None):

133
views.py
View File

@@ -5,6 +5,7 @@ import stat
import simplejson as json import simplejson as json
import re import re
import sys import sys
import urllib
import urllib2 import urllib2
from urllib import quote from urllib import quote
from django.core.urlresolvers import reverse 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 pysearpc import SearpcError
from seahub.base.accounts import CcnetUser from seahub.base.accounts import CcnetUser
from seahub.base.models import UuidOjbidMap
from seahub.contacts.models import Contact from seahub.contacts.models import Contact
from seahub.notifications.models import UserNotification from seahub.notifications.models import UserNotification
from forms import AddUserForm, FileLinkShareForm 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, \ get_httpserver_root, get_ccnetapplet_root, gen_token, \
calculate_repo_last_modify, valid_previewed_file, \ calculate_repo_last_modify, valid_previewed_file, \
check_filename_with_rename, get_accessible_repos, EMPTY_SHA1, \ 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 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 @login_required
def root(request): def root(request):
@@ -846,7 +849,7 @@ def repo_view_file(request, repo_id):
# determin whether file can preview on web # determin whether file can preview on web
filetype = valid_previewed_file(filename) filetype = valid_previewed_file(filename)
# raw path # raw path
raw_path = gen_file_get_url(token, filename) raw_path = gen_file_get_url(token, filename)
@@ -881,6 +884,7 @@ def repo_view_file(request, repo_id):
'protocol': http_or_https, 'protocol': http_or_https,
'domain': domain, 'domain': domain,
'file_shared_link': file_shared_link, 'file_shared_link': file_shared_link,
# 'doc_src': doc_src,
}, context_instance=RequestContext(request)) }, context_instance=RequestContext(request))
def repo_file_get(request, repo_id): def repo_file_get(request, repo_id):
@@ -1985,3 +1989,126 @@ def send_shared_link(request):
msg = '发送成功。' msg = '发送成功。'
data = json.dumps([{'msg': msg}]) data = json.dumps([{'msg': msg}])
return HttpResponse(data, status=200, content_type=content_type) 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)