From 02c44ea7ffb74f1be600e43e3b3d8753fd2739d1 Mon Sep 17 00:00:00 2001 From: liyawei Date: Tue, 12 Apr 2022 19:05:31 +0800 Subject: [PATCH] =?UTF-8?q?ocr=E8=AF=86=E5=88=AB-=E6=A0=A1=E6=A0=B8onlyoff?= =?UTF-8?q?ice=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/jero/config/shiro/ShiroConfig.java | 2 + jero-boot/jero-boot-modules/pom.xml | 11 + .../ocr/controller/OcrCheckController.java | 229 ++++++++ .../modules/ocr/entity/CommentGroups.java | 17 + .../jero/modules/ocr/entity/FileModel.java | 370 +++++++++++++ .../com/jero/modules/ocr/entity/FileType.java | 26 + .../com/jero/modules/ocr/entity/User.java | 48 ++ .../modules/ocr/helpers/ConfigManager.java | 61 ++ .../modules/ocr/helpers/CookieManager.java | 45 ++ .../modules/ocr/helpers/DocumentManager.java | 519 ++++++++++++++++++ .../jero/modules/ocr/helpers/FileUtility.java | 132 +++++ .../modules/ocr/helpers/ServiceConverter.java | 269 +++++++++ .../modules/ocr/helpers/TrackManager.java | 323 +++++++++++ .../com/jero/modules/ocr/helpers/Users.java | 110 ++++ .../src/main/resources/asstes/css/editor.css | 44 ++ .../src/main/resources/asstes/favicon.ico | Bin 0 -> 147237 bytes .../src/main/resources/settings.properties | 24 + .../src/main/resources/templates/editor.html | 127 +++++ .../src/main/resources/application-dev.yml | 11 +- 19 files changed, 2364 insertions(+), 4 deletions(-) create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/controller/OcrCheckController.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/CommentGroups.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileModel.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileType.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/User.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ConfigManager.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/CookieManager.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/DocumentManager.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/FileUtility.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ServiceConverter.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/TrackManager.java create mode 100644 jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/Users.java create mode 100644 jero-boot/jero-boot-modules/src/main/resources/asstes/css/editor.css create mode 100644 jero-boot/jero-boot-modules/src/main/resources/asstes/favicon.ico create mode 100644 jero-boot/jero-boot-modules/src/main/resources/settings.properties create mode 100644 jero-boot/jero-boot-modules/src/main/resources/templates/editor.html diff --git a/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java b/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java index ed55f5f39..6db7c1945 100644 --- a/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java +++ b/jero-boot/jero-boot-base/jero-boot-base-core/src/main/java/com/jero/config/shiro/ShiroConfig.java @@ -72,6 +72,8 @@ public class ShiroConfig { // 配置不会被拦截的链接 顺序判断 filterChainDefinitionMap.put("/sys/cas/client/validateLogin", "anon"); //cas验证登录 filterChainDefinitionMap.put("/ocr/OcrRestful/ocrHandleResult", "anon"); //ocr回调接口 + filterChainDefinitionMap.put("/ocr/ocrCheck/downFile", "anon"); //ocr校核下载文件 + filterChainDefinitionMap.put("/ocr/ocrCheck/saveFile", "anon"); //ocr校核回调 filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除 filterChainDefinitionMap.put("/sys/checkCaptcha", "anon"); //登录验证码接口排除 filterChainDefinitionMap.put("/sys/getRSAPublicKey", "anon"); //获取RSA公钥接口排除 diff --git a/jero-boot/jero-boot-modules/pom.xml b/jero-boot/jero-boot-modules/pom.xml index 82f9ecf17..d1605c902 100644 --- a/jero-boot/jero-boot-modules/pom.xml +++ b/jero-boot/jero-boot-modules/pom.xml @@ -150,6 +150,17 @@ org.springframework.boot spring-boot-starter-websocket + + + com.googlecode.json-simple + json-simple + 1.1 + + + com.inversoft + prime-jwt + 1.3.1 + diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/controller/OcrCheckController.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/controller/OcrCheckController.java new file mode 100644 index 000000000..e1f35b555 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/controller/OcrCheckController.java @@ -0,0 +1,229 @@ +package com.jero.modules.ocr.controller; + +import com.jero.common.exception.JeroBootException; +import com.jero.common.system.vo.LoginUser; +import com.jero.modules.ocr.helpers.ConfigManager; +import com.jero.modules.ocr.helpers.DocumentManager; +import com.jero.modules.ocr.helpers.FileUtility; +import com.jero.modules.ocr.helpers.ServiceConverter; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.apache.shiro.SecurityUtils; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Scanner; + +/** + * @Author: liyawei + * @Description: + * @Date: Created in 10:51 2022/4/11 + */ +@Api(tags="OCR识别在线校核") +@RestController +@RequestMapping("/ocr/ocrCheck") +@Slf4j +public class OcrCheckController { + + @Value("${OCR.ocrDownPath}") + private String ocrDownPath; + + @Value("${OCR.ocrSavePath}") + private String ocrSavePath; + + @Value("${OCR.serverUrl}") + private String serverUrl; + + @Value("${OCR.ocrPath}") + private String ocrPath; + + @ApiOperation(value = "下载word文件") + @GetMapping("/downFile") + public void downFile(String fileName, HttpServletResponse response, HttpServletRequest request) throws Exception { + InputStream is = null; + OutputStream os = null; + response.reset(); + try { + String downFileName = fileName.substring(fileName.indexOf("_") + 1); + response.setHeader("Content-Disposition", "attachment; filename=" + downFileName); + response.setContentType("application/octet-stream"); + + String fullPath = ocrPath + fileName; + is = new FileInputStream(fullPath); + os = response.getOutputStream(); + IOUtils.copy(is, os); + os.flush(); + } catch (FileNotFoundException var4) { + throw new JeroBootException("文件[" + ocrPath + fileName + "]不存在"); + } catch (IOException e) { + log.error(e.getMessage(), e); + } finally { + is.close(); + os.close(); + } + } + + @ApiOperation(value = "编辑文件") + @RequestMapping("/editorFile") + public ModelAndView index(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { + + String fileName = ""; + if (request.getParameterMap().containsKey("fileName")) { + fileName = request.getParameter("fileName"); + } +// String fileExt = null; +// if (request.getParameterMap().containsKey("fileExt")) { +// fileExt = request.getParameter("fileExt"); +// } + +// if (fileExt != null) { +// try { +// DocumentManager.Init(request, response); +// fileName = DocumentManager.CreateDemo(fileExt); +// } catch (Exception ex) { +// return new ModelAndView(new FastJsonJsonView(),"Error: " + ex.getMessage(), ex) ; +// } +// } + +// String mode = ""; +// if (request.getParameterMap().containsKey("mode")) +// { +// mode = request.getParameter("mode"); +// } +// Boolean desktopMode = !"embedded".equals(mode); + +// FileModel file = new FileModel(); +// file.SetTypeDesktop(desktopMode); +// file.SetFileName(fileName); + + log.info("==========EditorFile=========="); + DocumentManager.Init(request, response); + //要编辑的文件名 + model.addAttribute("fileName", fileName) ; + //要编辑的文件类型 + model.addAttribute("fileType", FileUtility.GetFileExtension(fileName).replace(".", "")) ; + //要编辑的文档类型 + model.addAttribute("documentType",FileUtility.GetFileType(fileName).toString().toLowerCase()) ; + //要编辑的文档访问url +// model.addAttribute("fileUri",DocumentManager.GetFileUri(fileName, true)) ; +// model.addAttribute("callbackUrl", DocumentManager.GetCallback(fileName)) ; +// model.addAttribute("serverUrl", DocumentManager.GetServerUrl(true)) ; + model.addAttribute("fileUri", ocrDownPath + "?fileName=" + fileName) ; + model.addAttribute("callbackUrl", ocrSavePath + "?fileName=" + fileName) ; + model.addAttribute("serverUrl", serverUrl) ; + model.addAttribute("fileKey", ServiceConverter.GenerateRevisionId(DocumentManager.CurUserHostAddress(null) + ocrDownPath + "?fileName=" + fileName)) ; + model.addAttribute("editorMode", DocumentManager.GetEditedExts().contains(FileUtility.GetFileExtension(fileName)) && !"view".equals(request.getAttribute("mode")) ? "edit" : "view") ; + model.addAttribute("editorUserId",DocumentManager.CurUserHostAddress(null)) ; + LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); + model.addAttribute("editorUserName", loginUser.getUsername()) ; + +// model.addAttribute("type", desktopMode ? "desktop" : "embedded"); + model.addAttribute("type", true ? "desktop" : "embedded"); + model.addAttribute("docserviceApiUrl", ConfigManager.GetProperty("files.docservice.url.api")); + model.addAttribute("docServiceUrlPreloader", ConfigManager.GetProperty("files.docservice.url.preloader")) ; + model.addAttribute("currentYear", "2022") ; + model.addAttribute("convertExts", String.join(",", DocumentManager.GetConvertExts())) ; + model.addAttribute("editedExts", String.join(",", DocumentManager.GetEditedExts())) ; + model.addAttribute("documentCreated", new SimpleDateFormat("MM/dd/yyyy").format(new Date())) ; + model.addAttribute("permissionsEdit", Boolean.toString(DocumentManager.GetEditedExts().contains(FileUtility.GetFileExtension(fileName))).toLowerCase()) ; + return new ModelAndView("editor") ; + } + + /** + * 文档编辑服务使用JavaScript API通知callbackUrl,向文档存储服务通知文档编辑的状态。文档编辑服务使用具有正文中的信息的POST请求。 + * https://api.onlyoffice.com/editors/callback + * 参数示例: + { + "actions": [{"type": 0, "userid": "78e1e841"}], + "changesurl": "https://documentserver/url-to-changes.zip", + "history": { + "changes": changes, + "serverVersion": serverVersion + }, + "key": "Khirz6zTPdfd7", + "status": 2, + "url": "https://documentserver/url-to-edited-document.docx", + "users": ["6d5a81d0"] + } + */ + @ApiOperation(value = "保存文件") + @RequestMapping("/saveFile") + public void saveFile(HttpServletRequest request, HttpServletResponse response) { + String fileName = ""; + if (request.getParameterMap().containsKey("fileName")) { + fileName = request.getParameter("fileName"); + } + PrintWriter writer = null; + log.info("==========SaveEditedFile=========="); + try { + writer = response.getWriter(); + Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A"); + String body = scanner.hasNext() ? scanner.next() : ""; + JSONObject jsonObj = (JSONObject) new JSONParser().parse(body); + log.info("status:" + jsonObj.get("status")); + /* + 0 - no document with the key identifier could be found, + 1 - document is being edited, + 2 - document is ready for saving, + 3 - document saving error has occurred, + 4 - document is closed with no changes, + 6 - document is being edited, but the current document state is saved, + 7 - error has occurred while force saving the document. + * */ + if ((long) jsonObj.get("status") == 2) { + /* + * 当我们关闭编辑窗口后,十秒钟左右onlyoffice会将它存储的我们的编辑后的文件,,此时status = 2,通过request发给我们,我们需要做的就是接收到文件然后回写该文件。 + * */ + + /* + * 定义要与文档存储服务保存的编辑文档的链接。当状态值仅等于2或3时,存在链路。 + * */ + String downloadUri = (String) jsonObj.get("url"); + log.info("文档编辑完成,现在开始保存编辑后的文档,其下载地址为:" + downloadUri); + //解析得出文件名 +// String fileName = downloadUri.substring(downloadUri.lastIndexOf('/') + 1); + log.info("下载的文件名:" + fileName); + + URL url = new URL(downloadUri); + java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); + InputStream stream = connection.getInputStream(); + + File savedFile = new File(ocrPath + fileName); + try (FileOutputStream out = new FileOutputStream(savedFile)) { + int read; + final byte[] bytes = new byte[1024]; + while ((read = stream.read(bytes)) != -1) { + out.write(bytes, 0, read); + } + out.flush(); + } + connection.disconnect(); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + /* + * status = 1,我们给onlyoffice的服务返回{"error":"0"}的信息,这样onlyoffice会认为回调接口是没问题的,这样就可以在线编辑文档了,否则的话会弹出窗口说明 + * */ + writer.write("{\"error\":0}"); + } +} diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/CommentGroups.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/CommentGroups.java new file mode 100644 index 000000000..4a6629f7c --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/CommentGroups.java @@ -0,0 +1,17 @@ +package com.jero.modules.ocr.entity; + +import java.util.List; + +public class CommentGroups { + public List view; + public List edit; + public List remove; + public CommentGroups(){ + + } + public CommentGroups(List view, List edit, List remove){ + this.view = view; + this.edit = edit; + this.remove = remove; + } +} diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileModel.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileModel.java new file mode 100644 index 000000000..d45af8a55 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileModel.java @@ -0,0 +1,370 @@ +/** + * + * (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.jero.modules.ocr.entity; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.jero.modules.ocr.helpers.DocumentManager; +import com.jero.modules.ocr.helpers.FileUtility; +import com.jero.modules.ocr.helpers.ServiceConverter; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +import java.io.File; +import java.io.FileInputStream; +import java.util.*; + +public class FileModel +{ + public String type = "desktop"; + public String mode = "edit"; + public String documentType; + public Document document; + public EditorConfig editorConfig; + public String token; + + // create file model + public FileModel(String fileName, String lang, String actionData, User user) + { + if (fileName == null) fileName = ""; + fileName = fileName.trim(); // remove extra spaces in the file name + + // get file type from the file name (word, cell or slide) + documentType = FileUtility.GetFileType(fileName).toString().toLowerCase(); + + // set the document parameters + document = new Document(); + document.title = fileName; + document.url = DocumentManager.GetDownloadUrl(fileName); // get file url + document.urlUser = DocumentManager.GetFileUri(fileName, false); + document.fileType = FileUtility.GetFileExtension(fileName).replace(".", ""); // get file extension from the file name + // generate document key + document.key = ServiceConverter.GenerateRevisionId(DocumentManager.CurUserHostAddress(null) + "/" + fileName + "/" + Long.toString(new File(DocumentManager.StoragePath(fileName, null)).lastModified())); + document.info = new Info(); + document.info.favorite = user.favorite; + + String templatesImageUrl = DocumentManager.GetTemplateImageUrl(FileUtility.GetFileType(fileName)); + List> templates = new ArrayList<>(); + String createUrl = DocumentManager.GetCreateUrl(FileUtility.GetFileType(fileName)); + + // add templates for the "Create New" from menu option + Map templateForBlankDocument = new HashMap<>(); + templateForBlankDocument.put("image", ""); + templateForBlankDocument.put("title", "Blank"); + templateForBlankDocument.put("url", createUrl); + templates.add(templateForBlankDocument); + Map templateForDocumentWithSampleContent = new HashMap<>(); + templateForDocumentWithSampleContent.put("image", templatesImageUrl); + templateForDocumentWithSampleContent.put("title", "With sample content"); + templateForDocumentWithSampleContent.put("url", createUrl + "&sample=true"); + templates.add(templateForDocumentWithSampleContent); + + // set the editor config parameters + editorConfig = new EditorConfig(actionData); + editorConfig.callbackUrl = DocumentManager.GetCallback(fileName); // get callback url + + if (lang != null) editorConfig.lang = lang; // write language parameter to the config + + editorConfig.createUrl = !user.id.equals("uid-0") ? createUrl : null; + editorConfig.templates = user.templates ? templates : null; + + // write user information to the config (id, name and group) + editorConfig.user.id = user.id; + editorConfig.user.name = user.name; + editorConfig.user.group = user.group; + + // write the absolute URL to the file location + editorConfig.customization.goback.url = DocumentManager.GetServerUrl(false) + "/IndexServlet"; + + changeType(mode, type, user); + } + + // change the document type + public void changeType(String _mode, String _type, User user) + { + if (_mode != null) mode = _mode; + if (_type != null) type = _type; + + // check if the file with such an extension can be edited + String fileExt = FileUtility.GetFileExtension(document.title); + Boolean canEdit = DocumentManager.GetEditedExts().contains(fileExt); + // check if the Submit form button is displayed or not + editorConfig.customization.submitForm = mode.equals("fillForms") && user.id.equals("uid-1") && false; + + if ((!canEdit && mode.equals("edit") || mode.equals("fillForms")) && DocumentManager.GetFillExts().contains(fileExt)) { + canEdit = true; + mode = "fillForms"; + } + // set the mode parameter: change it to view if the document can't be edited + editorConfig.mode = canEdit && !mode.equals("view") ? "edit" : "view"; + + // set document permissions + document.permissions = new Permissions(mode, type, canEdit, user); + + if (type.equals("embedded")) InitDesktop(); // set parameters for the embedded document + } + + public void InitDesktop() + { + editorConfig.InitDesktop(document.urlUser); + } + + // generate document token + public void BuildToken() + { + // write all the necessary document parameters to the map + Map map = new HashMap<>(); + map.put("type", type); + map.put("documentType", documentType); + map.put("document", document); + map.put("editorConfig", editorConfig); + + // and create token from them + token = DocumentManager.CreateToken(map); + } + + // get document history + public String[] GetHistory() + { + JSONParser parser = new JSONParser(); + String histDir = DocumentManager.HistoryDir(DocumentManager.StoragePath(document.title, null)); // get history directory + if (DocumentManager.GetFileVersion(histDir) > 0) { + Integer curVer = DocumentManager.GetFileVersion(histDir); // get current file version if it is greater than 0 + + List hist = new ArrayList<>(); + Map histData = new HashMap(); + + for (Integer i = 1; i <= curVer; i++) { // run through all the file versions + Map obj = new HashMap(); + Map dataObj = new HashMap(); + String verDir = DocumentManager.VersionDir(histDir, i); // get the path to the given file version + + try { + String key = null; + + // get document key + key = i == curVer ? document.key : readFileToEnd(new File(verDir + File.separator + "key.txt")); + + obj.put("key", key); + obj.put("version", i); + + if (i == 1) { // check if the version number is equal to 1 + String createdInfo = readFileToEnd(new File(histDir + File.separator + "createdInfo.json")); // get file with meta data + JSONObject json = (JSONObject) parser.parse(createdInfo); // and turn it into json object + + // write meta information to the object (user information and creation date) + obj.put("created", json.get("created")); + Map user = new HashMap(); + 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) { //check if the version number is greater than 1 + // if so, get the path to the changes.json file + JSONObject changes = (JSONObject) parser.parse(readFileToEnd(new File(DocumentManager.VersionDir(histDir, i - 1) + File.separator + "changes.json"))); + JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0); + + // write information about changes to the object + obj.put("changes", !change.isEmpty() ? changes.get("changes") : null); + obj.put("serverVersion", changes.get("serverVersion")); + obj.put("created", !change.isEmpty() ? change.get("created") : null); + obj.put("user", !change.isEmpty() ? change.get("user") : null); + + Map prev = (Map) histData.get(Integer.toString(i - 2)); // get the history data from the previous file version + Map prevInfo = new HashMap(); + prevInfo.put("key", prev.get("key")); // write key and url information about previous file version + prevInfo.put("url", prev.get("url")); + dataObj.put("previous", prevInfo); // write information about previous file version to the data object + // write the path to the diff.zip archive with differences in this file version + dataObj.put("changesUrl", DocumentManager.GetPathUri(DocumentManager.VersionDir(histDir, i - 1) + File.separator + "diff.zip")); + } + + if (DocumentManager.TokenEnabled()) + { + dataObj.put("token", DocumentManager.CreateToken(dataObj)); + } + + hist.add(obj); + histData.put(Integer.toString(i - 1), dataObj); + + } catch (Exception ex) { } + } + + // write history information about the current file version to the history object + Map histObj = new HashMap(); + histObj.put("currentVersion", curVer); + histObj.put("history", hist); + + Gson gson = new Gson(); + return new String[] { gson.toJson(histObj), gson.toJson(histData) }; + } + return new String[] { "", "" }; + } + + // read a file + private String readFileToEnd(File file) { + String output = ""; + try { + try(FileInputStream is = new FileInputStream(file)) + { + Scanner scanner = new Scanner(is); // read data from the source + scanner.useDelimiter("\\A"); + while (scanner.hasNext()) { + output += scanner.next(); + } + scanner.close(); + } + } catch (Exception e) { } + return output; + } + + // the document parameters + public class Document + { + public String title; + public String url; + public String urlUser; + public String fileType; + public String key; + public Info info; + public Permissions permissions; + } + + // the permissions parameters + public class Permissions + { + public Boolean comment; + public Boolean сopy; + public Boolean download; + public Boolean edit; + public Boolean print; + public Boolean fillForms; + public Boolean modifyFilter; + public Boolean modifyContentControl; + public Boolean review; + public List reviewGroups; + public CommentGroups commentGroups; + + // defines what can be done with a document + public Permissions(String mode, String type, Boolean canEdit, User user) + { + comment = !mode.equals("view") && !mode.equals("fillForms") && !mode.equals("embedded") && !mode.equals("blockcontent"); + сopy = !user.deniedPermissions.contains("сopy"); + download = !user.deniedPermissions.contains("download"); + edit = canEdit && (mode.equals("edit") || mode.equals("view") || mode.equals("filter") || mode.equals("blockcontent")); + print = !user.deniedPermissions.contains("print"); + fillForms = !mode.equals("view") && !mode.equals("comment") && !mode.equals("embedded") && !mode.equals("blockcontent"); + modifyFilter = !mode.equals("filter"); + modifyContentControl = !mode.equals("blockcontent"); + review = canEdit && (mode.equals("edit") || mode.equals("review")); + reviewGroups = user.reviewGroups; + commentGroups = user.commentGroups; + } + } + + // the Favorite icon state + public class Info + { + public Boolean favorite; + } + // the editor config parameters + public class EditorConfig + { + public HashMap actionLink = null; + public String mode = "edit"; + public String callbackUrl; + public String lang = "en"; + public String createUrl; + public List> templates; + public User user; + public Customization customization; + public Embedded embedded; + + public EditorConfig(String actionData) + { + // get the action in the document that will be scrolled to (bookmark or comment) + if (actionData != null) { + Gson gson = new Gson(); + actionLink = gson.fromJson(actionData, new TypeToken>() { }.getType()); + } + user = new User(); + customization = new Customization(); + } + + // set parameters for the embedded document + public void InitDesktop(String url) + { + embedded = new Embedded(); + embedded.saveUrl = url; // the absolute URL that will allow the document to be saved onto the user personal computer + embedded.embedUrl = url; // the absolute URL to the document serving as a source file for the document embedded into the web page + embedded.shareUrl = url; // the absolute URL that will allow other users to share this document + embedded.toolbarDocked = "top"; // the place for the embedded viewer toolbar, can be either top or bottom + } + + // default user parameters (id, name and group) + public class User + { + public String id; + public String name; + public String group; + } + + // customization parameters + 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; + } + } + + // parameters for embedded document + public class Embedded + { + public String saveUrl; + public String embedUrl; + public String shareUrl; + public String toolbarDocked; + } + } + + + // turn java objects into json strings + public static String Serialize(FileModel model) + { + Gson gson = new Gson(); + return gson.toJson(model); + } +} diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileType.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileType.java new file mode 100644 index 000000000..12f4162e4 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/FileType.java @@ -0,0 +1,26 @@ +/** + * + * (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.jero.modules.ocr.entity; + +public enum FileType +{ + Word, + Cell, + Slide +} \ No newline at end of file diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/User.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/User.java new file mode 100644 index 000000000..bb1933fd2 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/entity/User.java @@ -0,0 +1,48 @@ +/** + * + * (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.jero.modules.ocr.entity; + +import java.util.List; + +public class User { + public String id; + public String name; + public String email; + public String group; + public List reviewGroups; + public CommentGroups commentGroups; + public Boolean favorite; + public List deniedPermissions; + public List descriptions; + public Boolean templates; + + public User(String id, String name, String email, String group, List reviewGroups, CommentGroups commentGroups, + Boolean favorite, List deniedPermissions, List descriptions, Boolean templates) { + this.id = id; + this.name = name; + this.email = email; + this.group = group; + this.reviewGroups = reviewGroups; + this.commentGroups = commentGroups; + this.favorite = favorite; + this.deniedPermissions = deniedPermissions; + this.descriptions = descriptions; + this.templates = templates; + } +} \ No newline at end of file diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ConfigManager.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ConfigManager.java new file mode 100644 index 000000000..efddcd5fa --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ConfigManager.java @@ -0,0 +1,61 @@ +/** + * + * (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.jero.modules.ocr.helpers; + +import java.io.InputStream; +import java.util.Properties; + +public class ConfigManager +{ + private static Properties properties; + + static + { + Init(); + } + + private static void Init() + { + try + { + // get stream from the settings.properties resource and load it + properties = new Properties(); + InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("settings.properties"); + properties.load(stream); + } + catch (Exception ex) + { + properties = null; + } + } + + // get name from the settings.properties file + public static String GetProperty(String name) + { + if (properties == null) + { + return ""; + } + + // get property by its name + String property = properties.getProperty(name); + + return property == null ? "" : property; + } +} \ No newline at end of file diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/CookieManager.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/CookieManager.java new file mode 100644 index 000000000..39cd2eeb7 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/CookieManager.java @@ -0,0 +1,45 @@ +/** + * + * (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.jero.modules.ocr.helpers; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.HashMap; + +public class CookieManager { + private HashMap cookiesMap; + + public CookieManager(HttpServletRequest request) throws UnsupportedEncodingException { + cookiesMap = new HashMap(); + + Cookie[] cookies = request.getCookies(); // get all the cookies from the request + if (cookies != null) { + for (Cookie cookie : cookies) { // run through all the cookies + cookiesMap.putIfAbsent(cookie.getName(), URLDecoder.decode(cookie.getValue(), "UTF-8")); // add cookie to the cookies map if its name isn't in the map yet + } + } + } + + // get cookie by its name + public String getCookie(String name) { + return cookiesMap.get(name); + } +} \ No newline at end of file diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/DocumentManager.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/DocumentManager.java new file mode 100644 index 000000000..3f8433699 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/DocumentManager.java @@ -0,0 +1,519 @@ +/** + * + * (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.jero.modules.ocr.helpers; + +import com.jero.modules.ocr.entity.FileType; +import com.jero.modules.ocr.entity.User; +import org.json.simple.JSONObject; +import org.primeframework.jwt.Signer; +import org.primeframework.jwt.Verifier; +import org.primeframework.jwt.domain.JWT; +import org.primeframework.jwt.hmac.HMACSigner; +import org.primeframework.jwt.hmac.HMACVerifier; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.InetAddress; +import java.net.URLEncoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.*; + +public class DocumentManager +{ + private static HttpServletRequest request; + + public static void Init(HttpServletRequest req, HttpServletResponse resp) + { + request = req; + } + + // get max file size + public static long GetMaxFileSize() + { + long size; + + try + { + size = Long.parseLong(ConfigManager.GetProperty("filesize-max")); + } + catch (Exception ex) + { + size = 0; + } + + return size > 0 ? size : 5 * 1024 * 1024; + } + + // get all the supported file extensions + public static List GetFileExts() + { + List res = new ArrayList<>(); + + res.addAll(GetViewedExts()); + res.addAll(GetEditedExts()); + res.addAll(GetConvertExts()); + res.addAll(GetFillExts()); + + return res; + } + + public static List GetFillExts() { + String exts = ConfigManager.GetProperty("files.docservice.fill-docs"); + return Arrays.asList(exts.split("\\|")); + } + + // get file extensions that can be viewed + public static List GetViewedExts() + { + String exts = ConfigManager.GetProperty("files.docservice.viewed-docs"); + return Arrays.asList(exts.split("\\|")); + } + + // get file extensions that can be edited + public static List GetEditedExts() + { + String exts = ConfigManager.GetProperty("files.docservice.edited-docs"); + return Arrays.asList(exts.split("\\|")); + } + + // get file extensions that can be converted + public static List GetConvertExts() + { + String exts = ConfigManager.GetProperty("files.docservice.convert-docs"); + return Arrays.asList(exts.split("\\|")); + } + + // get current user host address + public static String CurUserHostAddress(String userAddress) + { + if(userAddress == null) + { + try + { + // use InetAddress class to get the user address if it wasn't passed to the function + userAddress = InetAddress.getLocalHost().getHostAddress(); + } + catch (Exception ex) + { + userAddress = ""; + } + } + + return userAddress.replaceAll("[^0-9a-zA-Z.=]", "_"); + } + + // get the root directory of the user host + public static String FilesRootPath(String userAddress) + { + String hostAddress = CurUserHostAddress(userAddress); // get current user host address + String serverPath = request.getSession().getServletContext().getRealPath(""); // get the server url + String storagePath = ConfigManager.GetProperty("storage-folder"); // get the storage directory + String directory = serverPath + storagePath + File.separator + hostAddress + File.separator; + + File file = new File(directory); + + // if the root directory doesn't exist + if (!file.exists()) + { + // create it + file.mkdirs(); + } + + return directory; + } + + // get the storage path of the file + public static String StoragePath(String fileName, String userAddress) + { + String directory = FilesRootPath(userAddress); + return directory + FileUtility.GetFileName(fileName); + } + + // get the path to the forcesaved file version + public static String ForcesavePath(String fileName, String userAddress, Boolean create) + { + String hostAddress = CurUserHostAddress(userAddress); + String serverPath = request.getSession().getServletContext().getRealPath(""); + String storagePath = ConfigManager.GetProperty("storage-folder"); + + // create the directory to this file version + String directory = serverPath + storagePath + File.separator + hostAddress + File.separator; + + File file = new File(directory); + if (!file.exists()) return ""; + + // create the directory to the history of this file version + directory = directory + fileName + "-hist" + File.separator; + file = new File(directory); + if (!create && !file.exists()) return ""; + + file.mkdirs(); + + directory = directory + fileName; + file = new File(directory); + if (!create && !file.exists()) { + return ""; + } + + return directory; + } + + // get the history directory + public static String HistoryDir(String storagePath) + { + return storagePath += "-hist"; + } + + // get the path to the file version by the history path and file version + public static String VersionDir(String histPath, Integer version) + { + return histPath + File.separator + Integer.toString(version); + } + + // get the path to the file version by the file name, user address and file version + public static String VersionDir(String fileName, String userAddress, Integer version) + { + return VersionDir(HistoryDir(StoragePath(fileName, userAddress)), version); + } + + // get the file version by the history path + public static Integer GetFileVersion(String historyPath) + { + File dir = new File(historyPath); + + if (!dir.exists()) return 1; // if the history path doesn't exist, then the file version is 1 + + File[] dirs = dir.listFiles(new FileFilter() { // take only directories from the history folder + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + + return dirs.length + 1; // count the directories + } + + // get the file version by the file name and user address + public static int GetFileVersion(String fileName, String userAddress) + { + return GetFileVersion(HistoryDir(StoragePath(fileName, userAddress))); + } + + // get a file name with an index if the file with such a name already exists + public static String GetCorrectName(String fileName, String userAddress) + { + String baseName = FileUtility.GetFileNameWithoutExtension(fileName); + String ext = FileUtility.GetFileExtension(fileName); + String name = baseName + ext; + + File file = new File(StoragePath(name, userAddress)); + + for (int i = 1; file.exists(); i++) // run through all the files with such a name in the storage directory + { + name = baseName + " (" + i + ")" + ext; // and add an index to the base name + file = new File(StoragePath(name, userAddress)); + } + + return name; + } + + // create meta information + public static void CreateMeta(String fileName, String uid, String uname, String userAddress) throws Exception + { + String histDir = HistoryDir(StoragePath(fileName, userAddress)); + + File dir = new File(histDir); // create history directory + dir.mkdir(); + + // create json object and put there file information (creation time, user id and name) + JSONObject json = new JSONObject(); + json.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + json.put("id", uid); + json.put("name", uname); + + // create createdInfo.json file with meta information in the history directory + File meta = new File(histDir + File.separator + "createdInfo.json"); + try (FileWriter writer = new FileWriter(meta)) { + json.writeJSONString(writer); // write information from the json object into this file + } + } + + // get all the stored files from the user host address + public static File[] GetStoredFiles(String userAddress) + { + String directory = FilesRootPath(userAddress); + + File file = new File(directory); + return file.listFiles(new FileFilter() { // take only files from the root directory + @Override + public boolean accept(File pathname) { + return pathname.isFile(); + } + }); + } + + // create demo document + public static String CreateDemo(String fileExt, Boolean sample, User user) throws Exception + { + String demoName = (sample ? "sample." : "new.") + fileExt; // create sample or new template file with the necessary extension + String demoPath = "assets" + File.separator + (sample ? "sample" : "new") + File.separator; // get the path to the sample document + String fileName = GetCorrectName(demoName, null); // get a file name with an index if the file with such a name already exists + + InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(demoPath + demoName); // get the input file stream + + CreateFile(Paths.get(StoragePath(fileName, null)), stream); + + // create meta information of the demo file + CreateMeta(fileName, user.id, user.name, null); + + return fileName; + } + + public static boolean CreateFile(Path path, InputStream stream) { + if (Files.exists(path)){ + return true; + } + try { + File file = Files.createFile(path).toFile(); + try (FileOutputStream out = new FileOutputStream(file)) + { + int read; + final byte[] bytes = new byte[1024]; + while ((read = stream.read(bytes)) != -1) + { + out.write(bytes, 0, read); + } + out.flush(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + // get file url + public static String GetFileUri(String fileName, Boolean forDocumentServer) + { + try + { + String serverPath = GetServerUrl(forDocumentServer); + String storagePath = ConfigManager.GetProperty("storage-folder"); + String hostAddress = CurUserHostAddress(null); + + String filePath = serverPath + "/" + storagePath + "/" + hostAddress + "/" + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()).replace("+", "%20"); +// String filePath = serverPath + "?fileName=" + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()).replace("+", "%20") + "&useraddress=" + hostAddress; + + return filePath; + } + catch (UnsupportedEncodingException e) + { + return ""; + } + } + + // get file information + public static ArrayList> GetFilesInfo(){ + ArrayList> files = new ArrayList<>(); + + // run through all the stored files + for(File file : GetStoredFiles(null)){ + Map map = new LinkedHashMap<>(); // write all the parameters to the map + map.put("version", GetFileVersion(file.getName(), null)); + map.put("id", ServiceConverter.GenerateRevisionId(CurUserHostAddress(null) + "/" + file.getName() + "/" + Long.toString(new File(StoragePath(file.getName(), null)).lastModified()))); + map.put("contentLength", new BigDecimal(String.valueOf((file.length()/1024.0))).setScale(2, RoundingMode.HALF_UP) + " KB"); + map.put("pureContentLength", file.length()); + map.put("title", file.getName()); + map.put("updated", String.valueOf(new Date(file.lastModified()))); + files.add(map); + } + + return files; + } + + // get file information by its id + public static ArrayList> GetFilesInfo(String fileId){ + ArrayList> file = new ArrayList<>(); + + for (Map map : GetFilesInfo()){ + if (map.get("id").equals(fileId)){ + file.add(map); + break; + } + } + + return file; + } + + // get the path url + public static String GetPathUri(String path) + { + String serverPath = GetServerUrl(true); + String storagePath = ConfigManager.GetProperty("storage-folder"); + String hostAddress = CurUserHostAddress(null); + + String filePath = serverPath + "/" + storagePath + "/" + hostAddress + "/" + path.replace(File.separator, "/").substring(FilesRootPath(null).length()).replace(" ", "%20"); + + return filePath; + } + + + // get the server url + public static String GetServerUrl(Boolean forDocumentServer) { + if (forDocumentServer && !ConfigManager.GetProperty("files.docservice.url.example").equals("")) { + return ConfigManager.GetProperty("files.docservice.url.example"); + } else { + return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); + } + } + + // get the callback url + public static String GetCallback(String fileName) + { + String serverPath = GetServerUrl(true); + String hostAddress = CurUserHostAddress(null); + try + { + String query = "?type=track&fileName=" + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()) + "&userAddress=" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()); + + return serverPath + "/IndexServlet" + query; + } + catch (UnsupportedEncodingException e) + { + return ""; + } + } + + // get url to the created file + public static String GetCreateUrl (FileType fileType) { + String serverPath = GetServerUrl(false); + String fileExt = GetInternalExtension(fileType).replace(".", ""); + String query = "?fileExt=" + fileExt; + + return serverPath + "/EditorServlet" + query; + } + + // get url to download a file + public static String GetDownloadUrl(String fileName) { + String serverPath = GetServerUrl(true); + String hostAddress = CurUserHostAddress(null); + try + { + String query = "?type=download&fileName=" + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()) + "&userAddress=" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()); + + return serverPath + "/IndexServlet" + query; + } + catch (UnsupportedEncodingException e) + { + return ""; + } + } + + // get an editor internal extension + public static String GetInternalExtension(FileType fileType) + { + // .docx for word file type + if (fileType.equals(FileType.Word)) + return ".docx"; + + // .xlsx for cell file type + if (fileType.equals(FileType.Cell)) + return ".xlsx"; + + // .pptx for slide file type + if (fileType.equals(FileType.Slide)) + return ".pptx"; + + // the default file type is .docx + return ".docx"; + } + + // get image url for templates + public static String GetTemplateImageUrl(FileType fileType) + { + String path = GetServerUrl(true) + "/css/img/"; + // for word file type + if (fileType.equals(FileType.Word)) + return path + "file_docx.svg"; + + // .xlsx for cell file type + if (fileType.equals(FileType.Cell)) + return path + "file_xlsx.svg"; + + // .pptx for slide file type + if (fileType.equals(FileType.Slide)) + return path + "file_pptx.svg"; + + // the default file type + return path + "file_docx.svg"; + } + + // create document token + public static String CreateToken(Map payloadClaims) + { + try + { + // build a HMAC signer using a SHA-256 hash + Signer signer = HMACSigner.newSHA256Signer(GetTokenSecret()); + JWT jwt = new JWT(); + for (String key : payloadClaims.keySet()) // run through all the keys from the payload + { + jwt.addClaim(key, payloadClaims.get(key)); // and write each claim to the jwt + } + return JWT.getEncoder().encode(jwt, signer); // sign and encode the JWT to a JSON string representation + } + catch (Exception e) + { + return ""; + } + } + + // read document token + public static JWT ReadToken(String token) + { + try + { + // build a HMAC verifier using the token secret + Verifier verifier = HMACVerifier.newVerifier(GetTokenSecret()); + return JWT.getDecoder().decode(token, verifier); // verify and decode the encoded string JWT to a rich object + } + catch (Exception exception) + { + return null; + } + } + + // check if the token is enabled + public static Boolean TokenEnabled() + { + String secret = GetTokenSecret(); + return secret != null && !secret.isEmpty(); + } + + // get token secret from the config parameters + public static String GetTokenSecret() + { + return ConfigManager.GetProperty("files.docservice.secret"); + } +} \ No newline at end of file diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/FileUtility.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/FileUtility.java new file mode 100644 index 000000000..46f1dd6bb --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/FileUtility.java @@ -0,0 +1,132 @@ +/** + * + * (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.jero.modules.ocr.helpers; + +import com.jero.modules.ocr.entity.FileType; + +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class FileUtility +{ + static {} + + // get file type + public static FileType GetFileType(String fileName) + { + String ext = GetFileExtension(fileName).toLowerCase(); + + // word type for document extensions + if (ExtsDocument.contains(ext)) + return FileType.Word; + + // cell type for spreadsheet extensions + if (ExtsSpreadsheet.contains(ext)) + return FileType.Cell; + + // slide type for presentation extensions + if (ExtsPresentation.contains(ext)) + return FileType.Slide; + + // default file type is word + return FileType.Word; + } + + // document extensions + public static List ExtsDocument = Arrays.asList + ( + ".doc", ".docx", ".docm", + ".dot", ".dotx", ".dotm", + ".odt", ".fodt", ".ott", ".rtf", ".txt", + ".html", ".htm", ".mht", ".xml", + ".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oxps", ".oform" + ); + + // spreadsheet extensions + public static List ExtsSpreadsheet = Arrays.asList + ( + ".xls", ".xlsx", ".xlsm", + ".xlt", ".xltx", ".xltm", + ".ods", ".fods", ".ots", ".csv" + ); + + // presentation extensions + public static List ExtsPresentation = Arrays.asList + ( + ".pps", ".ppsx", ".ppsm", + ".ppt", ".pptx", ".pptm", + ".pot", ".potx", ".potm", + ".odp", ".fodp", ".otp" + ); + + + // get file name from the url + public static String GetFileName(String url) + { + if (url == null) return ""; + + // get file name from the last part of url + String fileName = url.substring(url.lastIndexOf('/') + 1, url.length()); + fileName = fileName.split("\\?")[0]; + return fileName; + } + + // get file name without extension + public static String GetFileNameWithoutExtension(String url) + { + String fileName = GetFileName(url); + if (fileName == null) return null; + String fileNameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.')); + return fileNameWithoutExt; + } + + // get file extension from url + public static String GetFileExtension(String url) + { + String fileName = GetFileName(url); + if (fileName == null) return null; + String fileExt = fileName.substring(fileName.lastIndexOf(".")); + return fileExt.toLowerCase(); + } + + // get url parameters + public static Map GetUrlParams(String url) + { + try + { + String query = new URL(url).getQuery(); // take all the parameters which are placed after ? sign in the file url + String[] params = query.split("&"); // parameters are separated by & sign + Map map = new HashMap<>(); + for (String param : params) // write parameters and their values to the map dictionary + { + String name = param.split("=")[0]; + String value = param.split("=")[1]; + map.put(name, value); + } + return map; + } + catch (Exception ex) + { + return null; + } + } +} diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ServiceConverter.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ServiceConverter.java new file mode 100644 index 000000000..352270fdf --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/ServiceConverter.java @@ -0,0 +1,269 @@ +/** + * + * (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.jero.modules.ocr.helpers; + +import com.google.gson.Gson; +import com.jero.modules.ocr.util.UUIDUtils; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.*; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +public class ServiceConverter +{ + 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 region; + 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 + { + // get timeout value from the settings.properties + int timeout = Integer.parseInt(ConfigManager.GetProperty("files.docservice.timeout")); + if (timeout > 0) // if it's greater than 0 + { + ConvertTimeout = timeout; // assign this value to a convert timeout + } + } + catch (Exception ex) + { + } + } + + // get the url of the converted file + public static String GetConvertedUri(String documentUri, String fromExtension, String toExtension, String documentRevisionId, String filePass, Boolean isAsync, String lang) throws Exception + { + // check if the fromExtension parameter is defined; if not, get it from the document url + fromExtension = fromExtension == null || fromExtension.isEmpty() ? FileUtility.GetFileExtension(documentUri) : fromExtension; + + // check if the file name parameter is defined; if not, get random uuid for this file + String title = FileUtility.GetFileName(documentUri); + title = title == null || title.isEmpty() ? UUID.randomUUID().toString() : title; + + documentRevisionId = documentRevisionId == null || documentRevisionId.isEmpty() ? documentUri : documentRevisionId; + + documentRevisionId = GenerateRevisionId(documentRevisionId); // create document token + + // write all the necessary parameters to the body object + ConvertBody body = new ConvertBody(); + body.region = lang; + 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 map = new HashMap(); + map.put("region", lang); + 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); + + // add token to the body if it is enabled + String token = DocumentManager.CreateToken(map); + body.token = token; + + Map payloadMap = new HashMap(); + payloadMap.put("payload", map); // create payload object + headerToken = DocumentManager.CreateToken(payloadMap); // create header token + } + + Gson gson = new Gson(); + String bodyString = gson.toJson(body); + + byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8); + + // specify request parameters + 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); + + // write header token to the request + 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"); + + // convert string to json + String jsonString = ConvertStreamToString(stream); + + connection.disconnect(); + + return GetResponseUri(jsonString); + } + + // generate document key + public static String GenerateRevisionId(String expectedKey) + { + if (expectedKey.length() > 20) // if the expected key length is greater than 20 + expectedKey = Integer.toString(expectedKey.hashCode()); // the expected key is hashed and a fixed length value is stored in the string format + + String key = UUIDUtils.randomUUID(2) + expectedKey.replace("[^0-9-.a-zA-Z_=]", "_"); + + return key.substring(0, Math.min(key.length(), 20)); // the resulting key length is 20 or less + } + + // create an error message for an error code + private static void ProcessConvertServiceResponceError(int errorCode) throws Exception + { + String errorMessage = ""; + String errorMessageTemplate = "Error occurred in the ConvertService: "; + + // add the error message to the error message template depending on the error code + 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: // if the error code is equal to 0, the error message is empty + break; + default: + errorMessage = "ErrorCode = " + errorCode; // default value for the error message + break; + } + + throw new Exception(errorMessage); + } + + // get the response url + private static String GetResponseUri(String jsonString) throws Exception + { + JSONObject jsonObj = ConvertStringToJSON(jsonString); + + Object error = jsonObj.get("error"); + if (error != null) // if an error occurs + ProcessConvertServiceResponceError(Math.toIntExact((long)error)); // then get an error message + + // check if the conversion is completed and save the result to a variable + Boolean isEndConvert = (Boolean) jsonObj.get("endConvert"); + + Long resultPercent = 0l; + String responseUri = null; + + if (isEndConvert) // if the conversion is completed + { + resultPercent = 100l; + responseUri = (String) jsonObj.get("fileUrl"); // get the file url + } + else // if the conversion isn't completed + { + resultPercent = (Long) jsonObj.get("percent"); + resultPercent = resultPercent >= 100l ? 99l : resultPercent; // get the percentage value + } + + return resultPercent >= 100l ? responseUri : ""; + } + + // convert stream to string + public static String ConvertStreamToString(InputStream stream) throws IOException + { + InputStreamReader inputStreamReader = new InputStreamReader(stream); // create an object to get incoming stream + StringBuilder stringBuilder = new StringBuilder(); // create a string builder object + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); // create an object to read incoming streams + String line = bufferedReader.readLine(); // get incoming streams by lines + + while (line != null) + { + stringBuilder.append(line); // concatenate strings using the string builder + line = bufferedReader.readLine(); + } + + String result = stringBuilder.toString(); + + return result; + } + + // convert string to json + public static JSONObject ConvertStringToJSON(String jsonString) throws ParseException + { + JSONParser parser = new JSONParser(); + Object obj = parser.parse(jsonString); // parse json string + JSONObject jsonObj = (JSONObject) obj; // and turn it into a json object + + return jsonObj; + } +} \ No newline at end of file diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/TrackManager.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/TrackManager.java new file mode 100644 index 000000000..30f70155e --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/TrackManager.java @@ -0,0 +1,323 @@ +/** + * + * (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.jero.modules.ocr.helpers; + +import com.google.gson.Gson; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.primeframework.jwt.domain.JWT; + +import javax.servlet.http.HttpServletRequest; +import java.io.*; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Scanner; + +public class TrackManager { + private static final String DocumentJwtHeader = ConfigManager.GetProperty("files.docservice.header"); + + // read request body + public static JSONObject readBody(HttpServletRequest request, PrintWriter writer) throws Exception { + String bodyString = ""; + + try { + // read request body by streams + Scanner scanner = new Scanner(request.getInputStream()); + scanner.useDelimiter("\\A"); + bodyString = scanner.hasNext() ? scanner.next() : ""; + scanner.close(); + } + catch (Exception ex) { + writer.write("get request.getInputStream error:" + ex.getMessage()); + throw ex; + } + + // error when the bodyString object is empty + if (bodyString.isEmpty()) { + writer.write("empty request.getInputStream"); + throw new Exception("empty request.getInputStream"); + } + + JSONParser parser = new JSONParser(); + JSONObject body; + + try { + Object obj = parser.parse(bodyString); // parse bodyString object + body = (JSONObject) obj; + } catch (Exception ex) { + writer.write("JSONParser.parse error:" + ex.getMessage()); + throw ex; + } + + // if the secret key to generate token exists + if (DocumentManager.TokenEnabled()) { + String token = (String) body.get("token"); // get the document token + + if (token == null) { // if JSON web token is not received + String header = (String) request.getHeader(DocumentJwtHeader == null || DocumentJwtHeader.isEmpty() ? "Authorization" : DocumentJwtHeader); // get it from the Authorization header + if (header != null && !header.isEmpty()) { + token = header.startsWith("Bearer ") ? header.substring(7) : header; // and save it without Authorization prefix + } + } + + if (token == null || token.isEmpty()) { // if the token is not received + writer.write("{\"error\":1,\"message\":\"JWT expected\"}"); // an error occurs + throw new Exception("{\"error\":1,\"message\":\"JWT expected\"}"); + } + + JWT jwt = DocumentManager.ReadToken(token); // read token + if (jwt == null) { + writer.write("{\"error\":1,\"message\":\"JWT validation failed\"}"); // an error occurs + throw new Exception("{\"error\":1,\"message\":\"JWT validation failed\"}"); + } + + if (jwt.getObject("payload") != null) { // get the payload object from the request body + try { + @SuppressWarnings("unchecked") LinkedHashMap payload = + (LinkedHashMap)jwt.getObject("payload"); + + jwt.claims = payload; + } catch (Exception ex) { + writer.write("{\"error\":1,\"message\":\"Wrong payload\"}"); + throw ex; + } + } + + try { + Gson gson = new Gson(); + Object obj = parser.parse(gson.toJson(jwt.claims)); + body = (JSONObject) obj; + } catch (Exception ex) { + writer.write("JSONParser.parse error:" + ex.getMessage()); + throw ex; + } + } + + return body; + } + + // file saving process + public static void processSave(JSONObject body, String fileName, String userAddress) throws Exception { + if (body.get("url") == null) { + throw new Exception("DownloadUrl is null"); + } + String downloadUri = (String) body.get("url"); + String changesUri = (String) body.get("changesurl"); + String key = (String) body.get("key"); + String newFileName = fileName; + + String curExt = FileUtility.GetFileExtension(fileName); // get current file extension + String downloadExt = FileUtility.GetFileExtension(downloadUri); // get the extension of the downloaded file + + // convert downloaded file to the file with the current extension if these extensions aren't equal + if (!curExt.equals(downloadExt)) { + try { + String newFileUri = ServiceConverter.GetConvertedUri(downloadUri, downloadExt, curExt, ServiceConverter.GenerateRevisionId(downloadUri), null, false, null); // convert file and get url to a new file + if (newFileUri.isEmpty()) { + newFileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); // get the correct file name if it already exists + } else { + downloadUri = newFileUri; + } + } catch (Exception e){ + newFileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); + } + } + + String storagePath = DocumentManager.StoragePath(newFileName, userAddress); // get the file path + File histDir = new File(DocumentManager.HistoryDir(storagePath)); // get the path to the history direction + if (!histDir.exists()) histDir.mkdirs(); // if the path doesn't exist, create it + + String versionDir = DocumentManager.VersionDir(histDir.getAbsolutePath(), DocumentManager.GetFileVersion(histDir.getAbsolutePath())); // get the path to the file version + File ver = new File(versionDir); + File lastVersion = new File(DocumentManager.StoragePath(fileName, userAddress)); + File toSave = new File(storagePath); + + if (!ver.exists()) ver.mkdirs(); + + lastVersion.renameTo(new File(versionDir + File.separator + "prev" + curExt)); // get the path to the previous file version and rename the last file version with it + + downloadToFile(downloadUri, toSave); // save file to the storage path + downloadToFile(changesUri, new File(versionDir + File.separator + "diff.zip")); // save file changes to the diff.zip archive + + String history = (String) body.get("changeshistory"); + if (history == null && body.containsKey("history")) { + history = ((JSONObject) body.get("history")).toJSONString(); + } + if (history != null && !history.isEmpty()) { + FileWriter fw = new FileWriter(new File(versionDir + File.separator + "changes.json")); // write the history changes to the changes.json file + fw.write(history); + fw.close(); + } + + FileWriter fw = new FileWriter(new File(versionDir + File.separator + "key.txt")); // write the key value to the key.txt file + fw.write(key); + fw.close(); + + String forcesavePath = DocumentManager.ForcesavePath(newFileName, userAddress, false); // get the path to the forcesaved file version + if (!forcesavePath.equals("")) { // if the forcesaved file version exists + File forceSaveFile = new File(forcesavePath); + forceSaveFile.delete(); // remove it + } + } + + // file force saving process + public static void processForceSave(JSONObject body, String fileName, String userAddress) throws Exception { + if (body.get("url") == null) { + throw new Exception("DownloadUrl is null"); + } + String downloadUri = (String) body.get("url"); + + String curExt = FileUtility.GetFileExtension(fileName); // get current file extension + String downloadExt = FileUtility.GetFileExtension(downloadUri); // get the extension of the downloaded file + Boolean newFileName = false; + + // convert downloaded file to the file with the current extension if these extensions aren't equal + if (!curExt.equals(downloadExt)) { + try { + String newFileUri = ServiceConverter.GetConvertedUri(downloadUri, downloadExt, curExt, ServiceConverter.GenerateRevisionId(downloadUri), null, false, null); // convert file and get url to a new file + if (newFileUri.isEmpty()) { + newFileName = true; + } else { + downloadUri = newFileUri; + } + } catch (Exception e){ + newFileName = true; + } + } + + String forcesavePath = ""; + boolean isSubmitForm = body.get("forcesavetype").toString().equals("3"); // SubmitForm + + if (isSubmitForm) { // if the form is submitted + // new file + if (newFileName){ + fileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + "-form" + downloadExt, userAddress); // get the correct file name if it already exists + } else { + fileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + "-form" + curExt, userAddress); + } + forcesavePath = DocumentManager.StoragePath(fileName, userAddress); + } else { + if (newFileName){ + fileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); + } + + // create forcesave path if it doesn't exist + forcesavePath = DocumentManager.ForcesavePath(fileName, userAddress, false); + if (forcesavePath == "") { + forcesavePath = DocumentManager.ForcesavePath(fileName, userAddress, true); + } + } + + File toSave = new File(forcesavePath); + downloadToFile(downloadUri, toSave); + + if (isSubmitForm) { + JSONArray actions = (JSONArray) body.get("actions"); + JSONObject action = (JSONObject) actions.get(0); + String user = (String) action.get("userid"); // get the user id + DocumentManager.CreateMeta(fileName, user, "Filling Form", userAddress); // create meta data for forcesaved file + } + } + + // save file information from the url to the file specified + private static void downloadToFile(String url, File file) throws Exception { + if (url == null || url.isEmpty()) throw new Exception("argument url"); // url isn't specified + if (file == null) throw new Exception("argument path"); // file isn't specified + + URL uri = new URL(url); + java.net.HttpURLConnection connection = (java.net.HttpURLConnection) uri.openConnection(); + InputStream stream = connection.getInputStream(); // get input stream of the file information from the url + + if (stream == null) + { + throw new Exception("Stream is null"); + } + + try (FileOutputStream out = new FileOutputStream(file)) + { + int read; + final byte[] bytes = new byte[1024]; + while ((read = stream.read(bytes)) != -1) + { + out.write(bytes, 0, read); // write bytes to the output stream + } + + // force write data to the output stream that can be cached in the current thread + out.flush(); + } + + connection.disconnect(); + } + + // create a command request + public static void commandRequest(String method, String key) throws Exception { + String DocumentCommandUrl = ConfigManager.GetProperty("files.docservice.url.site") + ConfigManager.GetProperty("files.docservice.url.command"); + + URL url = new URL(DocumentCommandUrl); + java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); + + HashMap params = new HashMap(); + params.put("c", method); + params.put("key", key); + + String headerToken = ""; + if (DocumentManager.TokenEnabled()) // check if a secret key to generate token exists or not + { + Map payloadMap = new HashMap(); + payloadMap.put("payload", params); + headerToken = DocumentManager.CreateToken(payloadMap); // encode a payload object into a header token + + // add a header Authorization with a header token and Authorization prefix in it + connection.setRequestProperty(DocumentJwtHeader.equals("") ? "Authorization" : DocumentJwtHeader, "Bearer " + headerToken); + + String token = DocumentManager.CreateToken(params); // encode a payload object into a body token + params.put("token", token); + } + + Gson gson = new Gson(); + String bodyString = gson.toJson(params); + + byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8); + + connection.setRequestMethod("POST"); // set the request method + connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); // set the Content-Type header + connection.setDoOutput(true); // set the doOutput field to true + + connection.connect(); + try (OutputStream os = connection.getOutputStream()) { + os.write(bodyByte); // write bytes to the output stream + } + InputStream stream = connection.getInputStream();; // get input stream + + if (stream == null) + throw new Exception("Could not get an answer"); + + String jsonString = ServiceConverter.ConvertStreamToString(stream); // convert stream to json string + connection.disconnect(); + + JSONObject response = ServiceConverter.ConvertStringToJSON(jsonString); // convert json string to json object + if (!response.get("error").toString().equals("0")){ + throw new Exception(response.toJSONString()); + } + } +} diff --git a/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/Users.java b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/Users.java new file mode 100644 index 000000000..2c74f0079 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/java/com/jero/modules/ocr/helpers/Users.java @@ -0,0 +1,110 @@ +/** + * + * (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.jero.modules.ocr.helpers; + +import com.jero.modules.ocr.entity.CommentGroups; +import com.jero.modules.ocr.entity.User; + +import java.util.*; + +public class Users { + + static List descr_user_1 = new ArrayList() {{ + add("File author by default"); + add("Doesn’t belong to any group"); + add("Can review all the changes"); + add("Can perform all actions with comments"); + add("The file favorite state is undefined"); + add("Can create files from templates using data from the editor"); + }}; + + static List descr_user_2 = new ArrayList() {{ + add("Belongs to Group2"); + add("Can review only his own changes or changes made by users with no group"); + add("Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only"); + add("This file is marked as favorite"); + add("Can create new files from the editor"); + }}; + + static List descr_user_3 = new ArrayList() {{ + add("Belongs to Group3"); + add("Can review changes made by Group2 users"); + add("Can view comments left by Group2 and Group3 users. Can edit comments left by Group2 users"); + add("This file isn’t marked as favorite"); + add("Can’t copy data from the file to clipboard"); + add("Can’t download the file"); + add("Can’t print the file"); + add("Can create new files from the editor"); + }}; + + static List descr_user_0 = new ArrayList() {{ + add("The name is requested when the editor is opened"); + add("Doesn’t belong to any group"); + add("Can review all the changes"); + add("Can perform all actions with comments"); + add("The file favorite state is undefined"); + add("Can't mention others in comments"); + add("Can't create new files from the editor"); + }}; + + private static List users = new ArrayList() {{ + add(new User("uid-1", "John Smith", "smith@example.com", + null, null, new CommentGroups(), + null, new ArrayList(), descr_user_1, true)); + add(new User("uid-2", "Mark Pottato", "pottato@example.com", + "group-2", Arrays.asList("group-2", ""), new CommentGroups(null, Arrays.asList("group-2", ""), Arrays.asList("group-2")), + true, new ArrayList(), descr_user_2, false)); + add(new User("uid-3", "Hamish Mitchell", "mitchell@example.com", + "group-3", Arrays.asList("group-2"), new CommentGroups(Arrays.asList("group-3", "group-2"), Arrays.asList("group-2"), new ArrayList()), + false, Arrays.asList("copy", "download", "print"), descr_user_3, false)); + add(new User("uid-0", null, null, + null, null, new CommentGroups(), + null, new ArrayList(), descr_user_0, false)); + }}; + + // get a user by id specified + public static User getUser (String id) { + for (User user : users) { + if (user.id.equals(id)) { + return user; + } + } + return users.get(0); + } + + // get a list of all the users + public static List getAllUsers () { + return users; + } + + // get a list of users with their names and emails for mentions + public static List> getUsersForMentions (String id) { + List> usersData = new ArrayList<>(); + for (User user : users) { + if (!user.id.equals(id) && user.name != null && user.email != null) { + Map data = new HashMap<>(); + data.put("name", user.name); + data.put("email", user.email); + usersData.add(data); + } + } + return usersData; + } +} + diff --git a/jero-boot/jero-boot-modules/src/main/resources/asstes/css/editor.css b/jero-boot/jero-boot-modules/src/main/resources/asstes/css/editor.css new file mode 100644 index 000000000..9b66db3c8 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/resources/asstes/css/editor.css @@ -0,0 +1,44 @@ +/** + * + * (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. + * + */ + +html { + height: 100%; + width: 100%; +} + +body { + background: #fff; + color: #333; + font-family: Arial, Tahoma,sans-serif; + font-size: 12px; + font-weight: normal; + height: 100%; + margin: 0; + overflow-y: hidden; + padding: 0; + text-decoration: none; +} + +.form { + height: 100%; +} + +div { + margin: 0; + padding: 0; +} diff --git a/jero-boot/jero-boot-modules/src/main/resources/asstes/favicon.ico b/jero-boot/jero-boot-modules/src/main/resources/asstes/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dc87d1a88394e3aec8f283642442d2a85fb7bec1 GIT binary patch literal 147237 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 WZWFiWO#}mI$b@lIEH7G6w*DWe&UJwR literal 0 HcmV?d00001 diff --git a/jero-boot/jero-boot-modules/src/main/resources/settings.properties b/jero-boot/jero-boot-modules/src/main/resources/settings.properties new file mode 100644 index 000000000..0e4b38478 --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/resources/settings.properties @@ -0,0 +1,24 @@ +version=1.1.0 + +filesize-max=5242880 +storage-folder=D:\\OOFILES + +files.docservice.fill-docs=.oform|.docx +files.docservice.viewed-docs=.pdf|.djvu|.xps|.oxps +files.docservice.edited-docs=.docx|.xlsx|.csv|.pptx|.txt|.docxf +files.docservice.convert-docs=.docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2 +files.docservice.timeout=120000 + +files.docservice.url.site=http://172.29.96.1:9000/ +files.docservice.url.command=http://172.29.96.1:9000/coauthoring/CommandService.ashx + +files.docservice.url.converter= http://172.29.96.1:9000/ConvertService.ashx +files.docservice.url.tempstorage= http://172.29.96.1:9000/ResourceService.ashx +files.docservice.url.api= http://172.29.96.1:9000/web-apps/apps/api/documents/api.js +files.docservice.url.preloader= http://172.29.96.1:9000/web-apps/apps/api/documents/cache-scripts.html + +files.docservice.url.example= http://172.29.96.1:9000 + + +files.docservice.secret= +files.docservice.header=Authorization \ No newline at end of file diff --git a/jero-boot/jero-boot-modules/src/main/resources/templates/editor.html b/jero-boot/jero-boot-modules/src/main/resources/templates/editor.html new file mode 100644 index 000000000..1b16771cf --- /dev/null +++ b/jero-boot/jero-boot-modules/src/main/resources/templates/editor.html @@ -0,0 +1,127 @@ + + + + + ONLYOFFICE + + + + + + +
+
+
+ + \ No newline at end of file diff --git a/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml b/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml index 48ebeedd5..6878d07fb 100644 --- a/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml +++ b/jero-boot/jero-boot-single-startup/src/main/resources/application-dev.yml @@ -195,7 +195,7 @@ jero : path : #文件上传根目录 设置 upload: D://opt//upFiles - img: D://opt//upFiles + img: D://opt//upFiles/ #webapp文件路径 webapp: D://opt//webapp shiro: @@ -324,9 +324,12 @@ OCR: # OCR文件存储路径 ocrPath: D:/APPSOFT/LAWSOCRDEMO/OCRFILE/ #ocrPath: /data/DeploymentPackage/laws-shanqi/APPSOFT/LAWSOCRDEMO/OCRFILE/ - # OCR文件下载地址 -# ocrDownPath: http://139.9.235.66:9020/downfile/ - ocrDownPath: http://127.0.0.1:9020/downfile/ + # OCR文件下载地址(onlyoffice专用) + ocrDownPath: http://10.0.1.25:8080/jero-boot/ocr/ocrCheck/downFile + # OCR文件保存地址(onlyoffice专用) + ocrSavePath: http://10.0.1.25:8080/jero-boot/ocr/ocrCheck/saveFile + # OCR文件编辑失败返回列表页(onlyoffice专用) + serverUrl: http://10.0.1.25:3000/docManage/ocr # OCR接口超时时间 times: 20 # OCR转换类型