1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-31 14:42:10 +00:00

Merge pull request #5036 from haiwen/cad

Cad
This commit is contained in:
Daniel Pan
2021-11-23 11:56:54 +08:00
committed by GitHub
9 changed files with 406 additions and 0 deletions

1
media/js/GStarSDK.js Executable file

File diff suppressed because one or more lines are too long

0
seahub/cad/__init__.py Normal file
View File

14
seahub/cad/settings.py Normal file
View File

@@ -0,0 +1,14 @@
from django.conf import settings
ENABLE_CAD = getattr(settings, 'ENABLE_CAD', False)
CAD_MOBILE_SIZE_LIMIT = getattr(settings, 'CAD_MOBILE_SIZE_LIMIT', 5242880)
CAD_PC_SIZE_LIMIT = getattr(settings, 'CAD_PC_SIZE_LIMIT', 12582912)
CAD_HOST = getattr(settings, 'CAD_HOST', 'http://127.0.0.1:8000')
WEBCAD_ROOT_FOLDER = getattr(settings, 'WEBCAD_ROOT_FOLDER', '')
WEBCAD_DWG_PATH = getattr(settings, 'WEBCAD_DWG_PATH', 'file/dwg')
WEBCAD_OCF_PATH = getattr(settings, 'WEBCAD_OCF_PATH', 'file/ocf')
WEBCAD_HOST = getattr(settings, 'WEBCAD_HOST', '127.0.0.1')
WEBCAD_PORT = getattr(settings, 'WEBCAD_PORT', 3181)

9
seahub/cad/urls.py Normal file
View File

@@ -0,0 +1,9 @@
# Copyright (c) 2012-2016 Seafile Ltd.
from django.conf.urls import url
from .views import CadApiFileContentView
urlpatterns = [
# RESTful API
url(r'^api/file-content/$', CadApiFileContentView.as_view(), name='CadApiFileContentView'),
]

22
seahub/cad/utils.py Normal file
View File

@@ -0,0 +1,22 @@
import logging
from requests.models import PreparedRequest
from django.urls import reverse
from seahub.cad.settings import CAD_MOBILE_SIZE_LIMIT, CAD_PC_SIZE_LIMIT, \
CAD_HOST
# Get an instance of a logger
logger = logging.getLogger(__name__)
def get_cad_dict(request, username, repo_id, file_path):
return_dict = {}
return_dict['cad_mobile_size_limit'] = CAD_MOBILE_SIZE_LIMIT
return_dict['cad_pc_size_limit'] = CAD_PC_SIZE_LIMIT
req = PreparedRequest()
param_dict = {'repo_id': repo_id, 'file_path': file_path}
req.prepare_url(CAD_HOST + reverse('CadApiFileContentView'), param_dict)
return_dict['doc_url'] = req.url
return return_dict

178
seahub/cad/views.py Normal file
View File

@@ -0,0 +1,178 @@
# Copyright (c) 2012-2016 Seafile Ltd.
# encoding: utf-8
import os
import json
import socket
import logging
import posixpath
import urllib.parse
import urllib.request
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import SessionAuthentication
from django.http import HttpResponse
from seaserv import seafile_api
from seahub.api2.utils import api_error
from seahub.api2.throttling import UserRateThrottle
from seahub.api2.authentication import TokenAuthentication
from seahub.utils import gen_inner_file_get_url
from seahub.views import check_folder_permission
from seahub.cad.settings import WEBCAD_ROOT_FOLDER, \
WEBCAD_DWG_PATH, WEBCAD_OCF_PATH, WEBCAD_HOST, WEBCAD_PORT
logger = logging.getLogger(__name__)
def dwg_to_ocf(dwg_filename, ocf_filename):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as m:
logger.error(m)
return False
s.connect((WEBCAD_HOST, WEBCAD_PORT))
# send data to webcad
input_dict = {
"path": '',
"name": dwg_filename,
"ocf": ocf_filename,
"layout": "",
"utoken": "",
"taskClass": "MakeOcf",
"id": 1
}
message = {
"status": 0,
"host": "webcad",
"input": json.dumps(input_dict),
"output": ""
}
try:
s.sendall(bytes(json.dumps(message), encoding='utf-8'))
s.sendall(bytes(0))
except socket.error as m:
logger.error(m)
return False
# receive data
buffer = []
while True:
d = s.recv(1024)
if d:
buffer.append(d)
else:
break
rec_data = b''.join(buffer)
rec_str = rec_data.decode(encoding='utf-8')
s.close()
rec_json = json.loads(rec_str.strip('\x00'))
output_str = rec_json.get('output', '')
output_json = json.loads(output_str)
return output_json.get('msg', '') == 'OK'
class CadApiFileContentView(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,)
throttle_classes = (UserRateThrottle,)
def get(self, request, format=None):
""" get file content
"""
# parameter check
repo_id = request.GET.get('repo_id', None)
file_path = request.GET.get('file_path', None)
if not repo_id:
error_msg = 'repo_id invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
if not file_path:
error_msg = 'file_path invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# resource check
if not seafile_api.get_repo(repo_id):
error_msg = 'Library %s not found.' % repo_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
obj_id = seafile_api.get_file_id_by_path(repo_id, file_path)
if not obj_id:
error_msg = 'file %s not found.' % file_path
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# permission check
if not check_folder_permission(request, repo_id, '/'):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
# process dwg and ocf file
base_filename = "{}_{}_{}".format(repo_id, file_path, obj_id)
base_filename = urllib.parse.quote(base_filename, safe='')
dwg_filename = "{}.dwg".format(base_filename)
dwg_filepath = posixpath.join(WEBCAD_ROOT_FOLDER,
WEBCAD_DWG_PATH,
dwg_filename)
if not os.path.exists(dwg_filepath):
try:
fileserver_token = seafile_api.get_fileserver_access_token(repo_id,
obj_id,
'download',
request.user.username,
use_onetime=False)
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
if not fileserver_token:
logger.error('No fileserver token')
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
file_name = os.path.basename(file_path)
inner_path = gen_inner_file_get_url(fileserver_token, file_name)
try:
file_content = urllib.request.urlopen(inner_path).read()
except Exception as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
with open(dwg_filepath, 'wb') as f:
f.write(file_content)
ocf_filename = "{}.ocf".format(base_filename)
ocf_filepath = posixpath.join(WEBCAD_ROOT_FOLDER,
WEBCAD_OCF_PATH,
ocf_filename)
if not os.path.exists(ocf_filepath):
success = dwg_to_ocf(dwg_filename, ocf_filename)
if not success:
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
with open(ocf_filepath, 'rb') as f:
ocf_file_content = f.read()
return HttpResponse(ocf_file_content, content_type="application/octet-stream")

View File

@@ -0,0 +1,173 @@
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{filename}}</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
#webcad {
width: 100%;
height: 100%;
}
/*
如果不需要布局功能,可以取消这个注释,布局按钮就隐藏了。
电脑网页布局按钮隐藏
#GStarSDK-pc-toolsbar-floatbar-layout {
display: none;
}
*/
/*手机网页布局按钮隐藏
.GStarSDK #GStarSDK-panel-list li:nth-child(3) {
display: none;
}
*/
</style>
</head>
<body>
<div id="webcad"></div>
<script type="text/javascript" src="{{ MEDIA_URL }}js/GStarSDK.js"></script>
<script>
//先判断是否是IE浏览器IE10及以下的IE浏览器不支持直接弹出提示告知
window.onload = function () {
var browser = getBrowerInfo()
var ieversion = getIeVersion();
if (browser == 'IE') {
if (ieversion != '11.0') {
alert('不支持IE10及以下的浏览器请使用其他浏览器打开重试')
}
}
}
// 初始化SDK
var gstarSDK = new GStarSDK({
wrapId: 'webcad', //容器ID
switchLayoutCB: switchLayout, // 点击布局功能会触发此回调
apiHost: window.location.host, //API域名转换PDF、另存功能需要向该域名发送请求如果没有用的转PDF、版本转换功能则无须关注这个参数。
tipsTime: 3000, //错误提示信息存在时间(毫秒)默认30003秒
mobileSizeLimit: {{cad_mobile_size_limit}}, //移动端可打开ocf文件的最大限制字节数默认5242880(5M)
pcSizeLimit: {{cad_pc_size_limit}}, //PC端可打开ocf文件最大限制字节数默认12582912(12M)
sizeLimitCB: sizeLimit, //当ocf文件超过设置的最大值后执行该回调函数
language: 'zh', //语言设置,可选'zh'(简中)/'en'(英语)/'ko'(韩语),默认'zh'
measureAccuracy: 3, //测量数值的精度位数
mode: 'default', //填充显示模式,"default":默认值,粗文字不填充,其他填充图案正常填充;"line":所有元素都不填充;"fill":所有需要填充元素都填充
})
gstarSDK.enableZoom(5) // 开启鼠标缩放功能,数字是缩放的速度
gstarSDK.enablePan(1) // 开启鼠标平移功能
var fileId = "{{file_id}}"; //自定义,当前图纸的唯一标识
// 当ocf文件超过设置的最大值后执行这个函数里面逻辑可以自己定义
function sizeLimit(ocfSize, limitSize) {
alert('图纸太大,超过了系统设置的最大值')
//alert('图纸太大,当前图纸大小:' + parseInt(ocfSize / 1048576) + 'M,大于系统限制的:' + parseInt(limitSize / 1048576)+'M')
}
//测试用的ocf样例文件
var demoocfurl = {
'*MODEL_SPACE': 'https://resource-cn.gstarcad.com/sampledraw/0000012863.ocf',
'*PAPER_SPACE': 'https://resource-cn.gstarcad.com/sampledraw/0000012863.257.ocf',
}
// 初始化渲染默认ocf文件
//var defaultocfurl = 'http://127.0.0.1/file/ocf/1001/test.ocf' //默认显示的ocf文件url地址
//var defaultocfurl = demoocfurl['*MODEL_SPACE']
var defaultocfurl = "{{doc_url|safe}}";
getDrawSheet(defaultocfurl, function (arraybuffer) {
gstarSDK.render('ocf', arraybuffer, fileId, true)
})
// 切换布局回调方法
function switchLayout(obj) {
alert(obj.globalName) //布局名称
//var makeocfurl = 'http://127.0.0.1/transform.do?fileId=' + fileId + '&layout=' + obj.globalName //根据布局globalName获取相应布局名称由于布局图形必须有对应的布局名称后台才能转换生成需要将布局名传给后台然后后台返回转换后的ocf地址
//var layoutocfurl = getLayoutOcfUrl(makeocfurl)
var layoutocfurl = demoocfurl[String(obj.globalName)] //样例布局ocf文件
getDrawSheet(layoutocfurl, function (arraybuffer) {
gstarSDK.render('ocf', arraybuffer, fileId, true)
})
}
// 下载图纸数据
function getDrawSheet(url, cb) {
var req
if (window.XMLHttpRequest) {
req = new XMLHttpRequest()
} else {
req = new ActiveXObject('Microsoft.XMLHTTP')
}
gstarSDK.Tips.showProgress(0, '下载中...')
req.onload = function () {
if ((req.status >= 200 && req.status < 300) || req.status === 304) {
cb(req.response)
}
if (req.status === 404) {
gstarSDK.Tips.showProgress(0, url+' 此ocf文件下载失败')
}
}
req.open('GET', url, true)
req.responseType = 'arraybuffer'
req.send(null)
}
// 获取布局图纸转换请求链接返回的ocf地址
function getLayoutOcfUrl(url) {
var req
if (window.XMLHttpRequest) {
req = new XMLHttpRequest()
} else {
req = new ActiveXObject('Microsoft.XMLHTTP')
}
req.open('GET', url, false)
req.send(null)
req.onreadystatechange = function () {
if (req.status == 200 && req.readyState == 4) {
alert(req.responseText)
}
}
return req.responseText
}
//获取浏览器信息
function getBrowerInfo() {
var userAgent = window.navigator.userAgent.toLowerCase()
var browserType = ''
// 浏览器类型IE
if (userAgent.match(/msie/) != null || userAgent.match(/trident/) != null) {
browserType = 'IE'
}
return browserType
}
//获取IE浏览器版本
function getIeVersion() {
var IEMode = document.documentMode
var rMsie = /(msie\s|trident.*rv:)([\w.]+)/;
var ma = window.navigator.userAgent.toLowerCase()
var match = rMsie.exec(ma);
try {
return match[2];
} catch (e) {
return IEMode;
}
}
</script>
</body>
</html>

View File

@@ -199,6 +199,7 @@ urlpatterns = [
url(r'^oauth/', include('seahub.oauth.urls')),
url(r'^thirdparty-editor/', include('seahub.thirdparty_editor.urls')),
url(r'^ocm-via-webdav/', include('seahub.ocm_via_webdav.urls')),
url(r'^cad/', include('seahub.cad.urls')),
url(r'^$', react_fake_view, name='libraries'),
url(r'^robots\.txt$', TemplateView.as_view(template_name='robots.txt', content_type='text/plain')),

View File

@@ -880,6 +880,14 @@ def view_lib_file(request, repo_id, path):
send_file_access_msg(request, repo, path, 'web')
return render(request, template, return_dict)
elif getattr(settings, 'ENABLE_CAD', False) and path.endswith('.dwg'):
from seahub.cad.utils import get_cad_dict
cad_dict = get_cad_dict(request, username, repo_id, path)
return_dict.update(cad_dict)
return render(request, 'view_file_cad.html', return_dict)
else:
return_dict['err'] = "File preview unsupported"
return render(request, template, return_dict)