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:
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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:
|
||||||
|
@@ -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
10
urls.py
@@ -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')),
|
||||||
|
3
utils.py
3
utils.py
@@ -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
133
views.py
@@ -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)
|
||||||
|
Reference in New Issue
Block a user