feat(office文件预览): 高版本权限问题适配

This commit is contained in:
马超 2023-01-31 13:44:36 +08:00
parent 7fff22970f
commit b63a53834d
6 changed files with 14 additions and 568 deletions

11
pom.xml
View File

@ -111,6 +111,17 @@
<artifactId>jaudiotagger</artifactId>
</dependency>
<dependency>
<groupId>com.inversoft</groupId>
<artifactId>prime-jwt</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.2</version>
</dependency>
</dependencies>
<build>

View File

@ -418,7 +418,7 @@ public class FileController {
String md5Str = fileDealComp.getIdentifierByFile(fileUrl, fileBean.getStorageType());
fileService.updateFileDetail(userFile.getUserFileId(), md5Str, fileSize, sessionUserBean.getUserId());
fileService.updateFileDetail(userFile.getUserFileId(), md5Str, fileSize);
} catch (Exception e) {

View File

@ -42,7 +42,7 @@ public class User extends AbstractEntity {
public User(){}
public User(UserBean userBean) {
this.id = userBean.getUserId();
this.id = String.valueOf(userBean.getUserId());
this.name = userBean.getUsername();
this.group = "";

View File

@ -1,252 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.qiwenshare.file.service;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.qiwenshare.file.component.JwtComp;
import com.qiwenshare.file.helper.ConfigManager;
import com.qiwenshare.file.helper.DocumentManager;
import com.qiwenshare.file.helper.FileUtility;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Component
public class OfficeConverterService
{
@Resource
private JwtComp jwtComp;
private static int ConvertTimeout = 120000;
private static final String DocumentConverterUrl = ConfigManager.GetProperty("files.docservice.url.site") + ConfigManager.GetProperty("files.docservice.url.converter");
private static final String DocumentJwtHeader = ConfigManager.GetProperty("files.docservice.header");
public static class ConvertBody
{
public String url;
public String outputtype;
public String filetype;
public String title;
public String key;
public Boolean async;
public String token;
public String password;
}
static
{
try
{
int timeout = Integer.parseInt(ConfigManager.GetProperty("files.docservice.timeout"));
if (timeout > 0)
{
ConvertTimeout = timeout;
}
}
catch (Exception ex)
{
}
}
public String GetConvertedUri(String documentUri, String fromExtension, String toExtension, String documentRevisionId, String filePass, Boolean isAsync) throws Exception
{
fromExtension = fromExtension == null || fromExtension.isEmpty() ? FileUtility.GetFileExtension(documentUri) : fromExtension;
String title = FileUtility.GetFileName(documentUri);
title = title == null || title.isEmpty() ? UUID.randomUUID().toString() : title;
documentRevisionId = documentRevisionId == null || documentRevisionId.isEmpty() ? documentUri : documentRevisionId;
documentRevisionId = GenerateRevisionId(documentRevisionId);
ConvertBody body = new ConvertBody();
body.url = documentUri;
body.outputtype = toExtension.replace(".", "");
body.filetype = fromExtension.replace(".", "");
body.title = title;
body.key = documentRevisionId;
body.password = filePass;
if (isAsync)
body.async = true;
String headerToken = "";
if (DocumentManager.TokenEnabled())
{
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("url", body.url);
map.put("outputtype", body.outputtype);
map.put("filetype", body.filetype);
map.put("title", body.title);
map.put("key", body.key);
map.put("password", body.password);
if (isAsync)
map.put("async", body.async);
String token = jwtComp.createJWT(map);
body.token = token;
Map<String, Object> payloadMap = new HashMap<String, Object>();
payloadMap.put("payload", map);
headerToken = jwtComp.createJWT(payloadMap);
}
Gson gson = new Gson();
String bodyString = gson.toJson(body);
byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8);
URL url = new URL(DocumentConverterUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setFixedLengthStreamingMode(bodyByte.length);
connection.setRequestProperty("Accept", "application/json");
connection.setConnectTimeout(ConvertTimeout);
if (DocumentManager.TokenEnabled())
{
connection.setRequestProperty(DocumentJwtHeader.equals("") ? "Authorization" : DocumentJwtHeader, "Bearer " + headerToken);
}
connection.connect();
try (OutputStream os = connection.getOutputStream()) {
os.write(bodyByte);
}
InputStream stream = connection.getInputStream();
if (stream == null)
throw new Exception("Could not get an answer");
String jsonString = ConvertStreamToString(stream);
connection.disconnect();
return GetResponseUri(jsonString);
}
public static String GenerateRevisionId(String expectedKey)
{
if (expectedKey.length() > 20)
expectedKey = Integer.toString(expectedKey.hashCode());
String key = expectedKey.replace("[^0-9-.a-zA-Z_=]", "_");
return key.substring(0, Math.min(key.length(), 20));
}
private static void ProcessConvertServiceResponceError(int errorCode) throws Exception
{
String errorMessage = "";
String errorMessageTemplate = "Error occurred in the ConvertService: ";
switch (errorCode)
{
case -8:
errorMessage = errorMessageTemplate + "Error document VKey";
break;
case -7:
errorMessage = errorMessageTemplate + "Error document request";
break;
case -6:
errorMessage = errorMessageTemplate + "Error database";
break;
case -5:
errorMessage = errorMessageTemplate + "Incorrect password";
break;
case -4:
errorMessage = errorMessageTemplate + "Error download error";
break;
case -3:
errorMessage = errorMessageTemplate + "Error convertation error";
break;
case -2:
errorMessage = errorMessageTemplate + "Error convertation timeout";
break;
case -1:
errorMessage = errorMessageTemplate + "Error convertation unknown";
break;
case 0:
break;
default:
errorMessage = "ErrorCode = " + errorCode;
break;
}
throw new Exception(errorMessage);
}
private static String GetResponseUri(String jsonString) throws Exception
{
JSONObject jsonObj = ConvertStringToJSON(jsonString);
Object error = jsonObj.get("error");
if (error != null)
ProcessConvertServiceResponceError(Math.toIntExact((long)error));
Boolean isEndConvert = (Boolean) jsonObj.get("endConvert");
Long resultPercent = 0l;
String responseUri = null;
if (isEndConvert)
{
resultPercent = 100l;
responseUri = (String) jsonObj.get("fileUrl");
}
else
{
resultPercent = (Long) jsonObj.get("percent");
resultPercent = resultPercent >= 100l ? 99l : resultPercent;
}
return resultPercent >= 100l ? responseUri : "";
}
public static String ConvertStreamToString(InputStream stream) throws IOException
{
InputStreamReader inputStreamReader = new InputStreamReader(stream);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = bufferedReader.readLine();
while (line != null)
{
stringBuilder.append(line);
line = bufferedReader.readLine();
}
String result = stringBuilder.toString();
return result;
}
public static JSONObject ConvertStringToJSON(String jsonString)
{
return JSONObject.parseObject(jsonString);
}
}

View File

@ -1,313 +0,0 @@
/**
*
* (c) Copyright Ascensio System SIA 2021
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.qiwenshare.file.util;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.qiwenshare.file.helper.DocumentManager;
import com.qiwenshare.file.helper.FileUtility;
import lombok.Data;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Data
public class FileModel
{
public String type = "desktop";
public String mode = "edit";
public String documentType;
public Document document;
public EditorConfig editorConfig;
public String token;
public FileModel(String userFileId, String fileName, String fileUrl, String fileModifyTime, String uid, String uname, String callbackUrl, String mode)
{
if (fileName == null) fileName = "";
fileName = fileName.trim();
documentType = FileUtility.GetFileType(fileName).toString().toLowerCase();
document = new Document();
document.title = fileName;
document.url = fileUrl;
// document.urlUser = DocumentManager.GetFileUri(fileName, false);
document.fileType = FileUtility.GetFileExtension(fileName).replace(".", "");
document.key = Base64.getEncoder().encodeToString((userFileId + "_" + fileModifyTime).getBytes(StandardCharsets.UTF_8));
document.info = new Info();
document.info.favorite = uid != null && !uid.isEmpty() ? uid.equals("uid-2") : null;
editorConfig = new EditorConfig(null);
editorConfig.callbackUrl = callbackUrl;
// editorConfig.lang = null;
if (uid != null) editorConfig.user.id = uid;
if (uname != null) editorConfig.user.name = uid.equals("uid-0") ? null : uname;
if (editorConfig.user.id.equals("uid-2")) editorConfig.user.group = "group-2";
if (editorConfig.user.id.equals("uid-3")) editorConfig.user.group = "group-3";
// editorConfig.customization.goback.url = DocumentManager.GetServerUrl(false) + "/IndexServlet";
changeType(mode, type);
}
public void changeType(String _mode, String _type)
{
if (_mode != null) mode = _mode;
if (_type != null) type = _type;
Boolean canEdit = DocumentManager.GetEditedExts().contains(FileUtility.GetFileExtension(document.title));
editorConfig.customization.submitForm = canEdit && (mode.equals("edit") || mode.equals("fillForms"));
editorConfig.mode = canEdit && !mode.equals("view") ? "edit" : "view";
document.permissions = new Permissions(mode, type, canEdit);
if (type.equals("embedded")) InitDesktop();
}
public void InitDesktop()
{
editorConfig.InitDesktop(document.urlUser);
}
// public void BuildToken()
// {
// Map<String, Object> map = new HashMap<>();
// map.put("type", type);
// map.put("documentType", documentType);
// map.put("document", document);
// map.put("editorConfig", editorConfig);
//
// token = jwtComp.createJWT(map);
// }
// public String[] GetHistory()
// {
// String histDir = DocumentManager.HistoryDir(DocumentManager.StoragePath(document.title, null));
// if (DocumentManager.GetFileVersion(histDir) > 0) {
// Integer curVer = DocumentManager.GetFileVersion(histDir);
//
// List<Object> hist = new ArrayList<>();
// Map<String, Object> histData = new HashMap<String, Object>();
//
// for (Integer i = 1; i <= curVer; i++) {
// Map<String, Object> obj = new HashMap<String, Object>();
// Map<String, Object> dataObj = new HashMap<String, Object>();
// String verDir = DocumentManager.VersionDir(histDir, i);
//
// try {
// String key = null;
//
// key = i == curVer ? document.key : readFileToEnd(new File(verDir + File.separator + "key.txt"));
//
// obj.put("key", key);
// obj.put("version", i);
//
// if (i == 1) {
// String createdInfo = readFileToEnd(new File(histDir + File.separator + "createdInfo.json"));
// JSONObject json = JSONObject.parseObject(createdInfo);
// obj.put("created", json.get("created"));
// Map<String, Object> user = new HashMap<String, Object>();
// user.put("id", json.get("id"));
// user.put("name", json.get("name"));
// obj.put("user", user);
// }
//
// dataObj.put("key", key);
// dataObj.put("url", i == curVer ? document.url : DocumentManager.GetPathUri(verDir + File.separator + "prev" + FileUtility.GetFileExtension(document.title)));
// dataObj.put("version", i);
//
// if (i > 1) {
// JSONObject changes = JSONObject.parseObject(readFileToEnd(new File(DocumentManager.VersionDir(histDir, i - 1) + File.separator + "changes.json")));
// JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0);
//
// obj.put("changes", changes.get("changes"));
// obj.put("serverVersion", changes.get("serverVersion"));
// obj.put("created", change.get("created"));
// obj.put("user", change.get("user"));
//
// Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2));
// Map<String, Object> prevInfo = new HashMap<String, Object>();
// prevInfo.put("key", prev.get("key"));
// prevInfo.put("url", prev.get("url"));
// dataObj.put("previous", prevInfo);
// dataObj.put("changesUrl", DocumentManager.GetPathUri(DocumentManager.VersionDir(histDir, i - 1) + File.separator + "diff.zip"));
// }
//
// if (DocumentManager.TokenEnabled())
// {
// dataObj.put("token", jwtComp.createJWT(dataObj));
// }
//
// hist.add(obj);
// histData.put(Integer.toString(i - 1), dataObj);
//
// } catch (Exception ex) { }
// }
//
// Map<String, Object> histObj = new HashMap<String, Object>();
// histObj.put("currentVersion", curVer);
// histObj.put("history", hist);
//
// Gson gson = new Gson();
// return new String[] { gson.toJson(histObj), gson.toJson(histData) };
// }
// return new String[] { "", "" };
// }
private String readFileToEnd(File file) {
String output = "";
try {
try(FileInputStream is = new FileInputStream(file))
{
Scanner scanner = new Scanner(is);
scanner.useDelimiter("\\A");
while (scanner.hasNext()) {
output += scanner.next();
}
scanner.close();
}
} catch (Exception e) { }
return output;
}
@Data
public class Document
{
public String title;
public String url;
public String urlUser;
public String fileType;
public String key;
public Info info;
public Permissions permissions;
}
@Data
public class Permissions
{
public Boolean comment;
public Boolean download;
public Boolean edit;
public Boolean fillForms;
public Boolean modifyFilter;
public Boolean modifyContentControl;
public Boolean review;
public List<String> reviewGroups;
public Permissions(String mode, String type, Boolean canEdit)
{
comment = !mode.equals("view") && !mode.equals("fillForms") && !mode.equals("embedded") && !mode.equals("blockcontent");
download = true;
edit = canEdit && (mode.equals("edit") || mode.equals("view") || mode.equals("filter") || mode.equals("blockcontent"));
fillForms = !mode.equals("view") && !mode.equals("comment") && !mode.equals("embedded") && !mode.equals("blockcontent");
modifyFilter = !mode.equals("filter");
modifyContentControl = !mode.equals("blockcontent");
review = mode.equals("edit") || mode.equals("review");
reviewGroups = editorConfig.user.group != null ? GetReviewGroups(editorConfig.user.group) : null;
}
private List<String> GetReviewGroups(String group){
Map<String, List<String>> reviewGroups = new HashMap<>();
reviewGroups.put("group-2", Arrays.asList("group-2", ""));
reviewGroups.put("group-3", Arrays.asList("group-2"));
return reviewGroups.get(group);
}
}
@Data
public class Info
{
Boolean favorite;
}
public class EditorConfig
{
public HashMap<String, Object> actionLink = null;
public String mode = "edit";
public String callbackUrl;
public String lang = "en";
public User user;
public Customization customization;
public Embedded embedded;
public EditorConfig(String actionData)
{
if (actionData != null) {
Gson gson = new Gson();
actionLink = gson.fromJson(actionData, new TypeToken<HashMap<String, Object>>() { }.getType());
}
user = new User();
customization = new Customization();
}
public void InitDesktop(String url)
{
embedded = new Embedded();
embedded.saveUrl = url;
embedded.embedUrl = url;
embedded.shareUrl = url;
embedded.toolbarDocked = "top";
}
public class User
{
public String id = "uid-1";
public String name = "John Smith";
public String group = null;
}
public class Customization
{
public Goback goback;
public Boolean forcesave;
public Boolean submitForm;
public Customization()
{
forcesave = false;
goback = new Goback();
}
public class Goback
{
public String url;
}
}
public class Embedded
{
public String saveUrl;
public String embedUrl;
public String shareUrl;
public String toolbarDocked;
}
}
public static String Serialize(FileModel model)
{
Gson gson = new Gson();
return gson.toJson(model);
}
}

View File

@ -10,7 +10,7 @@ files.docservice.convert-docs=.docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|
files.docservice.timeout=120000
files.docservice.history.postfix=-hist
files.docservice.url.site=https://officeview.qiwenshare.com/
files.docservice.url.site=http://192.168.1.6:80/
files.docservice.url.converter=ConvertService.ashx
files.docservice.url.command=coauthoring/CommandService.ashx
files.docservice.url.api=web-apps/apps/api/documents/api.js