diff --git a/src/main/java/com/qiwenshare/file/api/IFileService.java b/src/main/java/com/qiwenshare/file/api/IFileService.java index d9766f2..77572e6 100644 --- a/src/main/java/com/qiwenshare/file/api/IFileService.java +++ b/src/main/java/com/qiwenshare/file/api/IFileService.java @@ -9,7 +9,7 @@ public interface IFileService extends IService { Long getFilePointCount(String fileId); void unzipFile(String userFileId, int unzipMode, String filePath); - void updateFileDetail(String userFileId, String identifier, long fileSize, long modifyUserId); + void updateFileDetail(String userFileId, String identifier, long fileSize); FileDetailVO getFileDetail(String userFileId); diff --git a/src/main/java/com/qiwenshare/file/controller/OfficeController.java b/src/main/java/com/qiwenshare/file/controller/OfficeController.java index 1661faf..65b0913 100644 --- a/src/main/java/com/qiwenshare/file/controller/OfficeController.java +++ b/src/main/java/com/qiwenshare/file/controller/OfficeController.java @@ -3,7 +3,6 @@ package com.qiwenshare.file.controller; import cn.hutool.core.util.IdUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.ClassUtils; import com.qiwenshare.common.exception.NotLoginException; import com.qiwenshare.common.result.RestResult; @@ -16,21 +15,26 @@ import com.qiwenshare.file.api.IUserService; import com.qiwenshare.file.component.FileDealComp; import com.qiwenshare.file.domain.FileBean; import com.qiwenshare.file.domain.UserFile; +import com.qiwenshare.file.domain.user.UserBean; import com.qiwenshare.file.dto.file.CreateOfficeFileDTO; import com.qiwenshare.file.dto.file.EditOfficeFileDTO; import com.qiwenshare.file.dto.file.PreviewOfficeFileDTO; -import com.qiwenshare.file.helper.ConfigManager; -import com.qiwenshare.file.util.FileModel; +import com.qiwenshare.file.office.documentserver.managers.history.HistoryManager; +import com.qiwenshare.file.office.documentserver.models.enums.Action; +import com.qiwenshare.file.office.documentserver.models.enums.Type; +import com.qiwenshare.file.office.documentserver.models.filemodel.FileModel; +import com.qiwenshare.file.office.entities.User; +import com.qiwenshare.file.office.services.configurers.FileConfigurer; +import com.qiwenshare.file.office.services.configurers.wrappers.DefaultFileWrapper; import com.qiwenshare.ufop.factory.UFOPFactory; import com.qiwenshare.ufop.operation.copy.Copier; import com.qiwenshare.ufop.operation.copy.domain.CopyFile; import com.qiwenshare.ufop.operation.download.domain.DownloadFile; -import com.qiwenshare.ufop.operation.write.Writer; -import com.qiwenshare.ufop.operation.write.domain.WriteFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; @@ -45,6 +49,7 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.URLDecoder; import java.util.List; +import java.util.Locale; import java.util.Scanner; import java.util.UUID; @@ -67,11 +72,20 @@ public class OfficeController { @Value("${ufop.storage-type}") private Integer storageType; + @Value("${files.docservice.url.site}") + private String docserviceSite; + + @Value("${files.docservice.url.api}") + private String docserviceApiUrl; + @Autowired + private FileConfigurer fileConfigurer; @Resource IFileService fileService; @Resource IUserFileService userFileService; + @Autowired + private HistoryManager historyManager; @Operation(summary = "创建office文件", description = "创建office文件", tags = {"office"}) @ResponseBody @@ -139,28 +153,38 @@ public class OfficeController { @Operation(summary = "预览office文件", description = "预览office文件", tags = {"office"}) @RequestMapping(value = "/previewofficefile", method = RequestMethod.POST) @ResponseBody - public RestResult previewOfficeFile(HttpServletRequest request, @RequestBody PreviewOfficeFileDTO previewOfficeFileDTO, @RequestHeader("token") String token) { + public RestResult previewOfficeFile(HttpServletRequest request, @RequestBody PreviewOfficeFileDTO previewOfficeFileDTO) { RestResult result = new RestResult<>(); try { JwtUser loginUser = SessionUtil.getSession(); UserFile userFile = userFileService.getById(previewOfficeFileDTO.getUserFileId()); - String baseUrl = request.getScheme()+"://"+ deploymentHost + ":" + port + request.getContextPath(); - String query = "?type=show&token="+token; - String callbackUrl = baseUrl + "/office/IndexServlet" + query; - FileModel file = new FileModel(userFile.getUserFileId(), - userFile.getFileName() + "." + userFile.getExtendName(), - previewOfficeFileDTO.getPreviewUrl(), - userFile.getUploadTime(), - String.valueOf(loginUser.getUserId()), - loginUser.getUsername(), - callbackUrl, - "view"); + + + UserBean userBean = userService.getById(loginUser.getUserId()); + User user = new User(userBean); + + Action action = Action.view; + Type type = Type.desktop; + Locale locale = new Locale("zh"); + FileModel fileModel = fileConfigurer.getFileModel( + DefaultFileWrapper + .builder() + .userFileId(userFile.getUserFileId()) + .fileName(userFile.getFileName() + "." + userFile.getExtendName()) + .type(type) + .lang(locale.toLanguageTag()) + .action(action) + .user(user) + .actionData(previewOfficeFileDTO.getPreviewUrl()) + .build() + ); JSONObject jsonObject = new JSONObject(); - jsonObject.put("file",file); - jsonObject.put("docserviceApiUrl", ConfigManager.GetProperty("files.docservice.url.site") + ConfigManager.GetProperty("files.docservice.url.api")); + jsonObject.put("file",fileModel); +// jsonObject.put("fileHistory", historyManager.getHistory(fileModel.getDocument())); // get file history and add it to the model + jsonObject.put("docserviceApiUrl", docserviceSite + docserviceApiUrl); jsonObject.put("reportName",userFile.getFileName()); result.setData(jsonObject); result.setCode(200); @@ -175,32 +199,35 @@ public class OfficeController { @Operation(summary = "编辑office文件", description = "编辑office文件", tags = {"office"}) @ResponseBody @RequestMapping(value = "/editofficefile", method = RequestMethod.POST) - public RestResult editOfficeFile(HttpServletRequest request, @RequestBody EditOfficeFileDTO editOfficeFileDTO, @RequestHeader("token") String token) { + public RestResult editOfficeFile(HttpServletRequest request, @RequestBody EditOfficeFileDTO editOfficeFileDTO) { RestResult result = new RestResult<>(); log.info("editOfficeFile"); try { - JwtUser loginUser = SessionUtil.getSession(); UserFile userFile = userFileService.getById(editOfficeFileDTO.getUserFileId()); - String baseUrl = request.getScheme()+"://"+ deploymentHost + ":" + port + request.getContextPath(); - log.info("回调地址baseUrl:" + baseUrl); - String query = "?type=edit&userFileId="+userFile.getUserFileId()+"&token="+token; - String callbackUrl = baseUrl + "/office/IndexServlet" + query; - - FileModel file = new FileModel(userFile.getUserFileId(), - userFile.getFileName() + "." + userFile.getExtendName(), - editOfficeFileDTO.getPreviewUrl(), - userFile.getUploadTime(), - String.valueOf(loginUser.getUserId()), - loginUser.getUsername(), - callbackUrl, - "edit"); + UserBean userBean = userService.getById(loginUser.getUserId()); + User user = new User(userBean); + Action action = Action.edit; + Type type = Type.desktop; + Locale locale = new Locale("zh"); + FileModel fileModel = fileConfigurer.getFileModel( + DefaultFileWrapper + .builder() + .userFileId(userFile.getUserFileId()) + .fileName(userFile.getFileName() + "." + userFile.getExtendName()) + .type(type) + .lang(locale.toLanguageTag()) + .action(action) + .user(user) + .actionData(editOfficeFileDTO.getPreviewUrl()) + .build() + ); JSONObject jsonObject = new JSONObject(); - jsonObject.put("file",file); - jsonObject.put("docserviceApiUrl",ConfigManager.GetProperty("files.docservice.url.site") + ConfigManager.GetProperty("files.docservice.url.api")); + jsonObject.put("file",fileModel); + jsonObject.put("docserviceApiUrl", docserviceSite + docserviceApiUrl); jsonObject.put("reportName",userFile.getFileName()); result.setData(jsonObject); result.setCode(200); @@ -234,7 +261,7 @@ public class OfficeController { String type = request.getParameter("type"); String downloadUri = (String) jsonObj.get("url"); - if("edit".equals(type)){//修改报告 + if("edit".equals(type)){ //修改报告 String userFileId = request.getParameter("userFileId"); UserFile userFile = userFileService.getById(userFileId); FileBean fileBean = fileService.getById(userFile.getFileId()); @@ -256,14 +283,14 @@ public class OfficeController { } finally { int fileLength = connection.getContentLength(); - log.info("当前修改文件大小为:" + Long.valueOf(fileLength)); + log.info("当前修改文件大小为:" + (long) fileLength); DownloadFile downloadFile = new DownloadFile(); downloadFile.setFileUrl(fileBean.getFileUrl()); InputStream inputStream = ufopFactory.getDownloader(fileBean.getStorageType()).getInputStream(downloadFile); String md5Str = DigestUtils.md5Hex(inputStream); - fileService.updateFileDetail(userFile.getUserFileId(), md5Str, fileLength, userId); + fileService.updateFileDetail(userFile.getUserFileId(), md5Str, fileLength); connection.disconnect(); } } @@ -275,6 +302,7 @@ public class OfficeController { }else { log.debug("状态为:0") ; writer.write("{\"error\":" + "0" + "}"); + } } diff --git a/src/main/java/com/qiwenshare/file/helper/ConfigManager.java b/src/main/java/com/qiwenshare/file/helper/ConfigManager.java deleted file mode 100644 index 4bf8486..0000000 --- a/src/main/java/com/qiwenshare/file/helper/ConfigManager.java +++ /dev/null @@ -1,60 +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.helper; - -import org.springframework.stereotype.Component; - -import java.io.InputStream; -import java.util.Properties; -@Component -public class ConfigManager -{ - private static Properties properties; - - static - { - Init(); - } - - private static void Init() - { - try - { - properties = new Properties(); - InputStream stream = ConfigManager.class.getResourceAsStream("/config/settings.properties"); - properties.load(stream); - } - catch (Exception ex) - { - properties = null; - } - } - - public static String GetProperty(String name) - { - if (properties == null) - { - return ""; - } - - String property = properties.getProperty(name); - - return property == null ? "" : property; - } -} \ No newline at end of file diff --git a/src/main/java/com/qiwenshare/file/helper/DocumentManager.java b/src/main/java/com/qiwenshare/file/helper/DocumentManager.java deleted file mode 100644 index 63005eb..0000000 --- a/src/main/java/com/qiwenshare/file/helper/DocumentManager.java +++ /dev/null @@ -1,371 +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.helper; - - -import com.alibaba.fastjson2.JSONObject; -import com.qiwenshare.file.component.JwtComp; -import com.qiwenshare.file.service.OfficeConverterService; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -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.text.SimpleDateFormat; -import java.util.*; - -@Component -public class DocumentManager -{ - @Resource - private JwtComp jwtComp; - @Resource - private OfficeConverterService officeConverterService; - private static HttpServletRequest request; - - public static void Init(HttpServletRequest req, HttpServletResponse resp) - { - request = req; - } - - 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; - } - - public static List GetFileExts() - { - List res = new ArrayList<>(); - - res.addAll(GetViewedExts()); - res.addAll(GetEditedExts()); - res.addAll(GetConvertExts()); - - return res; - } - - public static List GetViewedExts() - { - String exts = ConfigManager.GetProperty("files.docservice.viewed-docs"); - return Arrays.asList(exts.split("\\|")); - } - - public static List GetEditedExts() - { - String exts = ConfigManager.GetProperty("files.docservice.edited-docs"); - return Arrays.asList(exts.split("\\|")); - } - - public static List GetConvertExts() - { - String exts = ConfigManager.GetProperty("files.docservice.convert-docs"); - return Arrays.asList(exts.split("\\|")); - } - - public static String CurUserHostAddress(String userAddress) - { - if(userAddress == null) - { - try - { - userAddress = InetAddress.getLocalHost().getHostAddress(); - } - catch (Exception ex) - { - userAddress = ""; - } - } - - return userAddress.replaceAll("[^0-9a-zA-Z.=]", "_"); - } - - public static String FilesRootPath(String userAddress) - { - String hostAddress = CurUserHostAddress(userAddress); - String serverPath = request.getSession().getServletContext().getRealPath(""); - String storagePath = ConfigManager.GetProperty("storage-folder"); - String directory = serverPath + storagePath + File.separator + hostAddress + File.separator; - - File file = new File(directory); - - if (!file.exists()) - { - file.mkdirs(); - } - - return directory; - } - - public static String StoragePath(String fileName, String userAddress) - { - String directory = FilesRootPath(userAddress); - return directory + FileUtility.GetFileName(fileName); - } - - 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"); - - String directory = serverPath + storagePath + File.separator + hostAddress + File.separator; - - File file = new File(directory); - if (!file.exists()) return ""; - - 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; - } - - public static String HistoryDir(String storagePath) - { - return storagePath += "-hist"; - } - - public static String VersionDir(String histPath, Integer version) - { - return histPath + File.separator + Integer.toString(version); - } - - public static String VersionDir(String fileName, String userAddress, Integer version) - { - return VersionDir(HistoryDir(StoragePath(fileName, userAddress)), version); - } - - public static Integer GetFileVersion(String historyPath) - { - File dir = new File(historyPath); - - if (!dir.exists()) return 0; - - File[] dirs = dir.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.isDirectory(); - } - }); - - return dirs.length + 1; - } - - public static int GetFileVersion(String fileName, String userAddress) - { - return GetFileVersion(HistoryDir(StoragePath(fileName, userAddress))); - } - - 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++) - { - name = baseName + " (" + i + ")" + ext; - file = new File(StoragePath(name, userAddress)); - } - - return name; - } - - 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); - dir.mkdir(); - - JSONObject json = new JSONObject(); - json.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); - json.put("id", (uid == null || uid.isEmpty()) ? "uid-1" : uid); - if (json.get("id").equals("uid-0")) { - json.put("name", null); - } else { - json.put("name", (uname == null || uname.isEmpty()) ? "John Smith" : uname); - } - - File meta = new File(histDir + File.separator + "createdInfo.json"); - try (FileWriter writer = new FileWriter(meta)) { -// json.writeJSONString(writer); - } - } - - public static File[] GetStoredFiles(String userAddress) - { - String directory = FilesRootPath(userAddress); - - File file = new File(directory); - return file.listFiles(new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.isFile(); - } - }); - } - - public static String CreateDemo(String fileExt, Boolean sample, String uid, String uname) throws Exception - { - String demoName = (sample ? "sample." : "new.") + fileExt; - String demoPath = "assets" + File.separator + (sample ? "sample" : "new") + File.separator; - String fileName = GetCorrectName(demoName, null); - - InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(demoPath + demoName); - - File file = new File(StoragePath(fileName, 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); - } - out.flush(); - } - - CreateMeta(fileName, uid, uname, null); - - return fileName; - } - - 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"); - - return filePath; - } - catch (UnsupportedEncodingException e) - { - return ""; - } - } - - public ArrayList> GetFilesInfo(){ - ArrayList> files = new ArrayList<>(); - - for(File file : GetStoredFiles(null)){ - Map map = new LinkedHashMap<>(); - map.put("version", GetFileVersion(file.getName(), null)); - map.put("id", officeConverterService.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; - } - - public ArrayList> GetFilesInfo(String fileId){ - ArrayList> file = new ArrayList<>(); - - for (Map map : GetFilesInfo()){ - if (map.get("id").equals(fileId)){ - file.add(map); - break; - } - } - - return file; - } - - 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; - } - - - 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(); - } - } - - 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 ""; - } - } - - public static Boolean TokenEnabled() - { - String secret = GetTokenSecret(); - return secret != null && !secret.isEmpty(); - } - - private static String GetTokenSecret() - { - return ConfigManager.GetProperty("files.docservice.secret"); - } -} \ No newline at end of file diff --git a/src/main/java/com/qiwenshare/file/helper/FileUtility.java b/src/main/java/com/qiwenshare/file/helper/FileUtility.java deleted file mode 100644 index adc45b8..0000000 --- a/src/main/java/com/qiwenshare/file/helper/FileUtility.java +++ /dev/null @@ -1,121 +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.helper; - - - -import com.qiwenshare.file.constant.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 {} - - public static FileType GetFileType(String fileName) - { - String ext = GetFileExtension(fileName).toLowerCase(); - - if (ExtsDocument.contains(ext)) - return FileType.Word; - - if (ExtsSpreadsheet.contains(ext)) - return FileType.Cell; - - if (ExtsPresentation.contains(ext)) - return FileType.Slide; - - return FileType.Word; - } - - 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" - ); - - public static List ExtsSpreadsheet = Arrays.asList - ( - ".xls", ".xlsx", ".xlsm", - ".xlt", ".xltx", ".xltm", - ".ods", ".fods", ".ots", ".csv" - ); - - public static List ExtsPresentation = Arrays.asList - ( - ".pps", ".ppsx", ".ppsm", - ".ppt", ".pptx", ".pptm", - ".pot", ".potx", ".potm", - ".odp", ".fodp", ".otp" - ); - - - public static String GetFileName(String url) - { - if (url == null) return ""; - - String fileName = url.substring(url.lastIndexOf('/') + 1, url.length()); - fileName = fileName.split("\\?")[0]; - return fileName; - } - - public static String GetFileNameWithoutExtension(String url) - { - String fileName = GetFileName(url); - if (fileName == null) return null; - String fileNameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.')); - return fileNameWithoutExt; - } - - public static String GetFileExtension(String url) - { - String fileName = GetFileName(url); - if (fileName == null) return null; - String fileExt = fileName.substring(fileName.lastIndexOf(".")); - return fileExt.toLowerCase(); - } - - public static Map GetUrlParams(String url) - { - try - { - String query = new URL(url).getQuery(); - String[] params = query.split("&"); - Map map = new HashMap<>(); - for (String param : params) - { - String name = param.split("=")[0]; - String value = param.split("=")[1]; - map.put(name, value); - } - return map; - } - catch (Exception ex) - { - return null; - } - } -} diff --git a/src/main/java/com/qiwenshare/file/helper/TrackManager.java b/src/main/java/com/qiwenshare/file/helper/TrackManager.java deleted file mode 100644 index 17e3736..0000000 --- a/src/main/java/com/qiwenshare/file/helper/TrackManager.java +++ /dev/null @@ -1,299 +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.helper; - -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONArray; -import com.alibaba.fastjson2.JSONObject; -import com.google.gson.Gson; -import com.qiwenshare.file.component.JwtComp; -import com.qiwenshare.file.service.OfficeConverterService; -import io.jsonwebtoken.Claims; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; -import java.io.*; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.Scanner; - -@Component -public class TrackManager { - @Resource - private JwtComp jwtComp; - @Resource - private OfficeConverterService officeConverterService; - private static final String DocumentJwtHeader = ConfigManager.GetProperty("files.docservice.header"); - - public JSONObject readBody(HttpServletRequest request, PrintWriter writer) throws Exception { - String bodyString = ""; - - try { - 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; - } - - if (bodyString.isEmpty()) { - writer.write("empty request.getInputStream"); - throw new Exception("empty request.getInputStream"); - } - - JSONObject body; - - try { - body = JSONObject.parseObject(bodyString); - } catch (Exception ex) { - writer.write("JSONParser.parse error:" + ex.getMessage()); - throw ex; - } - - if (DocumentManager.TokenEnabled()) { - String token = (String) body.get("token"); - - if (token == null) { - String header = (String) request.getHeader(DocumentJwtHeader == null || DocumentJwtHeader.isEmpty() ? "Authorization" : DocumentJwtHeader); - if (header != null && !header.isEmpty()) { - token = header.startsWith("Bearer ") ? header.substring(7) : header; - } - } - - if (token == null || token.isEmpty()) { - writer.write("{\"error\":1,\"message\":\"JWT expected\"}"); - throw new Exception("{\"error\":1,\"message\":\"JWT expected\"}"); - } - - Claims claims = jwtComp.parseJWT(token); - try { - body = JSONObject.parseObject(JSON.toJSONString(claims)); - } catch (Exception ex) { - writer.write("JSONParser.parse error:" + ex.getMessage()); - throw ex; - } - - - if (body == null) { - writer.write("{\"error\":1,\"message\":\"JWT validation failed\"}"); - throw new Exception("{\"error\":1,\"message\":\"JWT validation failed\"}"); - } - - } - - return body; - } - - public void processSave(JSONObject body, String fileName, String userAddress) throws Exception { - 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); - String downloadExt = FileUtility.GetFileExtension(downloadUri); - - if (!curExt.equals(downloadExt)) { - try { - String newFileUri = officeConverterService.GetConvertedUri(downloadUri, downloadExt, curExt, officeConverterService.GenerateRevisionId(downloadUri), null, false); - if (newFileUri.isEmpty()) { - newFileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); - } else { - downloadUri = newFileUri; - } - } catch (Exception e){ - newFileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + downloadExt, userAddress); - } - } - - String storagePath = DocumentManager.StoragePath(newFileName, userAddress); - File histDir = new File(DocumentManager.HistoryDir(storagePath)); - if (!histDir.exists()) histDir.mkdirs(); - - String versionDir = DocumentManager.VersionDir(histDir.getAbsolutePath(), DocumentManager.GetFileVersion(histDir.getAbsolutePath())); - 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)); - - downloadToFile(downloadUri, toSave); - downloadToFile(changesUri, new File(versionDir + File.separator + "diff.zip")); - - 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")); - fw.write(history); - fw.close(); - } - - FileWriter fw = new FileWriter(new File(versionDir + File.separator + "key.txt")); - fw.write(key); - fw.close(); - - String forcesavePath = DocumentManager.ForcesavePath(newFileName, userAddress, false); - if (!forcesavePath.equals("")) { - File forceSaveFile = new File(forcesavePath); - forceSaveFile.delete(); - } - } - - public void processForceSave(JSONObject body, String fileName, String userAddress) throws Exception { - - String downloadUri = (String) body.get("url"); - - String curExt = FileUtility.GetFileExtension(fileName); - String downloadExt = FileUtility.GetFileExtension(downloadUri); - Boolean newFileName = false; - - if (!curExt.equals(downloadExt)) { - try { - String newFileUri = officeConverterService.GetConvertedUri(downloadUri, downloadExt, curExt, officeConverterService.GenerateRevisionId(downloadUri), null, false); - if (newFileUri.isEmpty()) { - newFileName = true; - } else { - downloadUri = newFileUri; - } - } catch (Exception e){ - newFileName = true; - } - } - - String forcesavePath = ""; - boolean isSubmitForm = body.get("forcesavetype").toString().equals("3"); - - if (isSubmitForm) { - //new file - if (newFileName){ - fileName = DocumentManager.GetCorrectName(FileUtility.GetFileNameWithoutExtension(fileName) + "-form" + downloadExt, userAddress); - } 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); - } - - 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"); - DocumentManager.CreateMeta(fileName, user, "Filling Form", userAddress); - } - } - - private static void downloadToFile(String url, File file) throws Exception { - if (url == null || url.isEmpty()) throw new Exception("argument url"); - if (file == null) throw new Exception("argument path"); - - URL uri = new URL(url); - java.net.HttpURLConnection connection = (java.net.HttpURLConnection) uri.openConnection(); - InputStream stream = connection.getInputStream(); - - 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); - } - - out.flush(); - } - - connection.disconnect(); - } - - public 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()) - { - Map payloadMap = new HashMap(); - payloadMap.put("payload", params); - headerToken = jwtComp.createJWT(payloadMap); - - connection.setRequestProperty(DocumentJwtHeader.equals("") ? "Authorization" : DocumentJwtHeader, "Bearer " + headerToken); - - String token = jwtComp.createJWT(params); - params.put("token", token); - } - - Gson gson = new Gson(); - String bodyString = gson.toJson(params); - - byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8); - - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); - connection.setDoOutput(true); - - 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 = officeConverterService.ConvertStreamToString(stream); - connection.disconnect(); - - JSONObject response = officeConverterService.ConvertStringToJSON(jsonString); - if (!response.get("error").toString().equals("0")){ - throw new Exception(response.toJSONString()); - } - } -} diff --git a/src/main/java/com/qiwenshare/file/office/controllers/EditorController.java b/src/main/java/com/qiwenshare/file/office/controllers/EditorController.java new file mode 100644 index 0000000..a74e6f5 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/controllers/EditorController.java @@ -0,0 +1,191 @@ +package com.qiwenshare.file.office.controllers;///** +// * +// * (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.office.controllers; +// +//import com.fasterxml.jackson.core.JsonProcessingException; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.onlyoffice.integration.documentserver.managers.history.HistoryManager; +//import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager; +//import com.onlyoffice.integration.documentserver.models.enums.Action; +//import com.onlyoffice.integration.documentserver.models.enums.Type; +//import com.onlyoffice.integration.documentserver.models.filemodel.FileModel; +//import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; +//import com.onlyoffice.integration.dto.Mentions; +//import com.onlyoffice.integration.entities.User; +//import com.onlyoffice.integration.services.UserServices; +//import com.onlyoffice.integration.services.configurers.FileConfigurer; +//import com.onlyoffice.integration.services.configurers.wrappers.DefaultFileWrapper; +//import lombok.SneakyThrows; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.stereotype.Controller; +//import org.springframework.ui.Model; +//import org.springframework.web.bind.annotation.CookieValue; +//import org.springframework.web.bind.annotation.CrossOrigin; +//import org.springframework.web.bind.annotation.GetMapping; +//import org.springframework.web.bind.annotation.RequestParam; +// +//import java.util.*; +// +//@CrossOrigin("*") +//@Controller +//public class EditorController { +// +// @Value("${files.docservice.url.site}") +// private String docserviceSite; +// +// @Value("${files.docservice.url.api}") +// private String docserviceApiUrl; +// +// @Value("${files.docservice.languages}") +// private String langs; +// +// @Autowired +// private FileStoragePathBuilder storagePathBuilder; +// +// @Autowired +// private JwtManager jwtManager; +// +// @Autowired +// private UserServices userService; +// +// @Autowired +// private HistoryManager historyManager; +// +// @Autowired +// private ObjectMapper objectMapper; +// +// @Autowired +// private FileConfigurer fileConfigurer; +// +// @GetMapping(path = "${url.editor}") +// // process request to open the editor page +// public String index(@RequestParam("fileName") String fileName, +// @RequestParam(value = "action", required = false) String actionParam, +// @RequestParam(value = "type", required = false) String typeParam, +// @RequestParam(value = "actionLink", required = false) String actionLink, +// @CookieValue(value = "uid") String uid, +// @CookieValue(value = "ulang") String lang, +// Model model) throws JsonProcessingException { +// Action action = Action.edit; +// Type type = Type.desktop; +// Locale locale = new Locale("en"); +// +// if(actionParam != null) action = Action.valueOf(actionParam); +// if(typeParam != null) type = Type.valueOf(typeParam); +// +// List langsAndKeys = Arrays.asList(langs.split("\\|")); +// for (String langAndKey : langsAndKeys) { +// String[] couple = langAndKey.split(":"); +// if (couple[0].equals(lang)) { +// String[] langAndCountry = couple[0].split("-"); +// locale = new Locale(langAndCountry[0], langAndCountry.length > 1 ? langAndCountry[1] : ""); +// } +// } +// +// Optional optionalUser = userService.findUserById(Integer.parseInt(uid)); +// +// // if the user is not present, return the ONLYOFFICE start page +// if(!optionalUser.isPresent()) return "index.html"; +// +// User user = optionalUser.get(); +// +// // get file model with the default file parameters +// FileModel fileModel = fileConfigurer.getFileModel( +// DefaultFileWrapper +// .builder() +// .fileName(fileName) +// .type(type) +// .lang(locale.toLanguageTag()) +// .action(action) +// .user(user) +// .actionData(actionLink) +// .build() +// ); +// +// // add attributes to the specified model +// model.addAttribute("model", fileModel); // add file model with the default parameters to the original model +// model.addAttribute("fileHistory", historyManager.getHistory(fileModel.getDocument())); // get file history and add it to the model +// model.addAttribute("docserviceApiUrl",docserviceSite + docserviceApiUrl); // create the document service api URL and add it to the model +// model.addAttribute("dataInsertImage", getInsertImage()); // get an image and add it to the model +// model.addAttribute("dataCompareFile", getCompareFile()); // get a document for comparison and add it to the model +// model.addAttribute("dataMailMergeRecipients", getMailMerge()); // get recipients data for mail merging and add it to the model +// model.addAttribute("usersForMentions", getUserMentions(uid)); // get user data for mentions and add it to the model +// return "editor.html"; +// } +// +// private List getUserMentions(String uid){ // get user data for mentions +// List usersForMentions=new ArrayList<>(); +// if(uid!=null && !uid.equals("4")) { +// List list = userService.findAll(); +// for (User u : list) { +// if (u.getId()!=Integer.parseInt(uid) && u.getId()!=4) { +// usersForMentions.add(new Mentions(u.getName(),u.getEmail())); // user data includes user names and emails +// } +// } +// } +// +// return usersForMentions; +// } +// +// @SneakyThrows +// private String getInsertImage() { // get an image that will be inserted into the document +// Map dataInsertImage = new HashMap<>(); +// dataInsertImage.put("fileType", "png"); +// dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.png"); +// dataInsertImage.put("directUrl", storagePathBuilder.getServerUrl(false) + "/css/img/logo.png"); +// +// // check if the document token is enabled +// if(jwtManager.tokenEnabled()){ +// dataInsertImage.put("token", jwtManager.createToken(dataInsertImage)); // create token from the dataInsertImage object +// } +// +// return objectMapper.writeValueAsString(dataInsertImage).substring(1, objectMapper.writeValueAsString(dataInsertImage).length()-1); +// } +// +// @SneakyThrows +// private String getCompareFile(){ // get a document that will be compared with the current document +// Map dataCompareFile = new HashMap<>(); +// dataCompareFile.put("fileType", "docx"); +// dataCompareFile.put("url", storagePathBuilder.getServerUrl(true) + "/assets?name=sample.docx"); +// dataCompareFile.put("directUrl", storagePathBuilder.getServerUrl(false) + "/assets?name=sample.docx"); +// +// // check if the document token is enabled +// if(jwtManager.tokenEnabled()){ +// dataCompareFile.put("token", jwtManager.createToken(dataCompareFile)); // create token from the dataCompareFile object +// } +// +// return objectMapper.writeValueAsString(dataCompareFile); +// } +// +// @SneakyThrows +// private String getMailMerge(){ +// Map dataMailMergeRecipients = new HashMap<>(); // get recipients data for mail merging +// dataMailMergeRecipients.put("fileType", "csv"); +// dataMailMergeRecipients.put("url", storagePathBuilder.getServerUrl(true) + "/csv"); +// dataMailMergeRecipients.put("directUrl", storagePathBuilder.getServerUrl(false) + "/csv"); +// +// // check if the document token is enabled +// if(jwtManager.tokenEnabled()){ +// dataMailMergeRecipients.put("token", jwtManager.createToken(dataMailMergeRecipients)); // create token from the dataMailMergeRecipients object +// } +// +// return objectMapper.writeValueAsString(dataMailMergeRecipients); +// } +//} diff --git a/src/main/java/com/qiwenshare/file/office/controllers/FileController.java b/src/main/java/com/qiwenshare/file/office/controllers/FileController.java new file mode 100644 index 0000000..7cbebd2 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/controllers/FileController.java @@ -0,0 +1,400 @@ +package com.qiwenshare.file.office.controllers;///** +// * +// * (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.office.controllers; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.onlyoffice.integration.documentserver.callbacks.CallbackHandler; +//import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager; +//import com.onlyoffice.integration.documentserver.managers.document.DocumentManager; +//import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager; +//import com.onlyoffice.integration.documentserver.models.enums.DocumentType; +//import com.onlyoffice.integration.documentserver.storage.FileStorageMutator; +//import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; +//import com.onlyoffice.integration.documentserver.util.file.FileUtility; +//import com.onlyoffice.integration.documentserver.util.service.ServiceConverter; +//import com.onlyoffice.integration.dto.Converter; +//import com.onlyoffice.integration.dto.Track; +//import com.onlyoffice.integration.entities.User; +//import com.onlyoffice.integration.services.UserServices; +//import org.json.simple.JSONObject; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.core.io.Resource; +//import org.springframework.http.HttpHeaders; +//import org.springframework.http.MediaType; +//import org.springframework.http.ResponseEntity; +//import org.springframework.stereotype.Controller; +//import org.springframework.ui.Model; +//import org.springframework.web.bind.annotation.*; +//import org.springframework.web.multipart.MultipartFile; +// +//import javax.servlet.http.HttpServletRequest; +//import java.io.IOException; +//import java.io.InputStream; +//import java.net.URL; +//import java.net.URLEncoder; +//import java.nio.charset.StandardCharsets; +//import java.nio.file.Path; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.Map; +//import java.util.Optional; +// +//@CrossOrigin("*") +//@Controller +//public class FileController { +// +// @Value("${files.docservice.header}") +// private String documentJwtHeader; +// +// @Value("${filesize-max}") +// private String filesizeMax; +// +// @Value("${files.docservice.url.site}") +// private String docserviceUrlSite; +// +// @Value("${files.docservice.url.command}") +// private String docserviceUrlCommand; +// +// @Autowired +// private FileUtility fileUtility; +// @Autowired +// private DocumentManager documentManager; +// @Autowired +// private JwtManager jwtManager; +// @Autowired +// private FileStorageMutator storageMutator; +// @Autowired +// private FileStoragePathBuilder storagePathBuilder; +// @Autowired +// private UserServices userService; +// @Autowired +// private CallbackHandler callbackHandler; +// @Autowired +// private ObjectMapper objectMapper; +// @Autowired +// private ServiceConverter serviceConverter; +// @Autowired +// private CallbackManager callbackManager; +// +// // create user metadata +// private String createUserMetadata(String uid, String fullFileName) { +// Optional optionalUser = userService.findUserById(Integer.parseInt(uid)); // find a user by their ID +// String documentType = fileUtility.getDocumentType(fullFileName).toString().toLowerCase(); // get document type +// if(optionalUser.isPresent()){ +// User user = optionalUser.get(); +// storageMutator.createMeta(fullFileName, // create meta information with the user ID and name specified +// String.valueOf(user.getId()), user.getName()); +// } +// return "{ \"filename\": \"" + fullFileName + "\", \"documentType\": \"" + documentType + "\" }"; +// } +// +// // download data from the specified file +// private ResponseEntity downloadFile(String fileName){ +// Resource resource = storageMutator.loadFileAsResource(fileName); // load the specified file as a resource +// String contentType = "application/octet-stream"; +// +// // create a response with the content type, header and body with the file data +// return ResponseEntity.ok() +// .contentType(MediaType.parseMediaType(contentType)) +// .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") +// .body(resource); +// } +// +// // download data from the specified history file +// private ResponseEntity downloadFileHistory(String fileName, String version, String file){ +// Resource resource = storageMutator.loadFileAsResourceHistory(fileName,version,file); // load the specified file as a resource +// String contentType = "application/octet-stream"; +// +// // create a response with the content type, header and body with the file data +// return ResponseEntity.ok() +// .contentType(MediaType.parseMediaType(contentType)) +// .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") +// .body(resource); +// } +// +// @PostMapping("/upload") +// @ResponseBody +// public String upload(@RequestParam("file") MultipartFile file, // upload a file +// @CookieValue("uid") String uid){ +// try { +// String fullFileName = file.getOriginalFilename(); // get file name +// String fileExtension = fileUtility.getFileExtension(fullFileName); // get file extension +// long fileSize = file.getSize(); // get file size +// byte[] bytes = file.getBytes(); // get file in bytes +// +// // check if the file size exceeds the maximum file size or is less than 0 +// if(fileUtility.getMaxFileSize() < fileSize || fileSize <= 0){ +// return "{ \"error\": \"File size is incorrect\"}"; // if so, write an error message to the response +// } +// +// // check if file extension is supported by the editor +// if(!fileUtility.getFileExts().contains(fileExtension)){ +// return "{ \"error\": \"File type is not supported\"}"; // if not, write an error message to the response +// } +// +// String fileNamePath = storageMutator.updateFile(fullFileName, bytes); // update a file +// if (fileNamePath.isBlank()){ +// throw new IOException("Could not update a file"); // if the file cannot be updated, an error occurs +// } +// +// fullFileName = fileUtility.getFileNameWithoutExtension(fileNamePath) + fileExtension; // get full file name +// +// return createUserMetadata(uid, fullFileName); // create user metadata and return it +// } catch (Exception e) { +// e.printStackTrace(); +// } +// return "{ \"error\": \"Something went wrong when uploading the file.\"}"; // if the operation of file uploading is unsuccessful, an error occurs +// } +// +// @PostMapping(path = "${url.converter}") +// @ResponseBody +// public String convert(@RequestBody Converter body, // convert a file +// @CookieValue("uid") String uid, @CookieValue("ulang") String lang){ +// String fileName = body.getFileName(); // get file name +// String fileUri = documentManager.getDownloadUrl(fileName, true); // get URL for downloading a file with the specified name +// String filePass = body.getFilePass() != null ? body.getFilePass() : null; // get file password if it exists +// String fileExt = fileUtility.getFileExtension(fileName); // get file extension +// DocumentType type = fileUtility.getDocumentType(fileName); // get document type (word, cell or slide) +// String internalFileExt = fileUtility.getInternalExtension(type); // get an editor internal extension (".docx", ".xlsx" or ".pptx") +// +// try{ +// if(fileUtility.getConvertExts().contains(fileExt)){ // check if the file with such an extension can be converted +// String key = serviceConverter.generateRevisionId(fileUri); // generate document key +// String newFileUri = serviceConverter // get the URL to the converted file +// .getConvertedUri(fileUri, fileExt, internalFileExt, key, filePass, true, lang); +// +// if(newFileUri.isEmpty()){ +// return "{ \"step\" : \"0\", \"filename\" : \"" + fileName + "\"}"; +// } +// +// // get a file name of an internal file extension with an index if the file with such a name already exists +// String nameWithInternalExt = fileUtility.getFileNameWithoutExtension(fileName) + internalFileExt; +// String correctedName = documentManager.getCorrectName(nameWithInternalExt); +// +// URL url = new URL(newFileUri); +// java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); +// InputStream stream = connection.getInputStream(); // get input stream of the converted file +// +// if (stream == null){ +// connection.disconnect(); +// throw new RuntimeException("Input stream is null"); +// } +// +// // create the converted file with input stream +// storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(correctedName)), stream); +// fileName = correctedName; +// } +// +// // create meta information about the converted file with the user ID and name specified +// return createUserMetadata(uid, fileName); +// }catch (Exception e) { +// e.printStackTrace(); +// } +// return "{ \"error\": \"" + "The file can't be converted.\"}"; // if the operation of file converting is unsuccessful, an error occurs +// } +// +// @PostMapping("/delete") +// @ResponseBody +// public String delete(@RequestBody Converter body){ // delete a file +// try +// { +// String fullFileName = fileUtility.getFileName(body.getFileName()); // get full file name +// boolean fileSuccess = storageMutator.deleteFile(fullFileName); // delete a file from the storage and return the status of this operation (true or false) +// boolean historySuccess = storageMutator.deleteFileHistory(fullFileName); // delete file history and return the status of this operation (true or false) +// +// return "{ \"success\": \""+ (fileSuccess && historySuccess) +"\"}"; +// } +// catch (Exception e) +// { +// return "{ \"error\": \"" + e.getMessage() + "\"}"; // if the operation of file deleting is unsuccessful, an error occurs +// } +// } +// +// @GetMapping("/downloadhistory") +// public ResponseEntity downloadHistory(HttpServletRequest request,// download a file +// @RequestParam("fileName") String fileName, +// @RequestParam("ver") String version, +// @RequestParam("file") String file){ // history file +// try{ +// // check if a token is enabled or not +// if(jwtManager.tokenEnabled()){ +// String header = request.getHeader(documentJwtHeader == null // get the document JWT header +// || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader); +// if(header != null && !header.isEmpty()){ +// String token = header.replace("Bearer ", ""); // token is the header without the Bearer prefix +// jwtManager.readToken(token); // read the token +// }else { +// return null; +// } +// } +// return downloadFileHistory(fileName,version,file); // download data from the specified file +// } catch(Exception e){ +// return null; +// } +// } +// +// @GetMapping(path = "${url.download}") +// public ResponseEntity download(HttpServletRequest request, // download a file +// @RequestParam("fileName") String fileName){ +// try{ +// // check if a token is enabled or not +// if(jwtManager.tokenEnabled()){ +// String header = request.getHeader(documentJwtHeader == null // get the document JWT header +// || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader); +// if(header != null && !header.isEmpty()){ +// String token = header.replace("Bearer ", ""); // token is the header without the Bearer prefix +// jwtManager.readToken(token); // read the token +// } +// } +// return downloadFile(fileName); // download data from the specified file +// } catch(Exception e){ +// return null; +// } +// } +// +// @GetMapping("/create") +// public String create(@RequestParam("fileExt") String fileExt, // create a sample file of the specified extension +// @RequestParam(value = "sample", required = false) Optional isSample, +// @CookieValue(value = "uid", required = false) String uid, +// Model model){ +// Boolean sampleData = (isSample.isPresent() && !isSample.isEmpty()) && isSample.get(); // specify if the sample data exists or not +// if(fileExt != null){ +// try{ +// Optional user = userService.findUserById(Integer.parseInt(uid)); // find a user by their ID +// if (!user.isPresent()) throw new RuntimeException("Could not fine any user with id = "+uid); // if the user with the specified ID doesn't exist, an error occurs +// String fileName = documentManager.createDemo(fileExt, sampleData, uid, user.get().getName()); // create a demo document with the sample data +// if (fileName.isBlank() || fileName == null) { +// throw new RuntimeException("You must have forgotten to add asset files"); +// } +// return "redirect:editor?fileName=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8); // redirect the request +// }catch (Exception ex){ +// model.addAttribute("error", ex.getMessage()); +// return "error.html"; +// } +// } +// return "redirect:/"; +// } +// +// @GetMapping("/assets") +// public ResponseEntity assets(@RequestParam("name") String name) // get sample files from the assests +// { +// String fileName = Path.of("assets", "sample", fileUtility.getFileName(name)).toString(); +// return downloadFile(fileName); +// } +// +// @GetMapping("/csv") +// public ResponseEntity csv() // download a csv file +// { +// String fileName = Path.of("assets", "sample", "csv.csv").toString(); +// return downloadFile(fileName); +// } +// +// @GetMapping("/files") +// @ResponseBody +// public ArrayList> files(@RequestParam(value = "fileId", required = false) String fileId){ // get files information +// return fileId == null ? documentManager.getFilesInfo() : documentManager.getFilesInfo(fileId); +// } +// +// @PostMapping(path = "${url.track}") +// @ResponseBody +// public String track(HttpServletRequest request, // track file changes +// @RequestParam("fileName") String fileName, +// @RequestParam("userAddress") String userAddress, +// @RequestBody Track body){ +// try { +// String bodyString = objectMapper.writeValueAsString(body); // write the request body to the object mapper as a string +// String header = request.getHeader(documentJwtHeader == null // get the request header +// || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader); +// +// if (bodyString.isEmpty()) { // if the request body is empty, an error occurs +// throw new RuntimeException("{\"error\":1,\"message\":\"Request payload is empty\"}"); +// } +// +// JSONObject bodyCheck = jwtManager.parseBody(bodyString, header); // parse the request body +// body = objectMapper.readValue(bodyCheck.toJSONString(), Track.class); // read the request body +// } catch (Exception e) { +// e.printStackTrace(); +// return e.getMessage(); +// } +// +// int error = callbackHandler.handle(body, fileName); +// +// return"{\"error\":" + error + "}"; +// } +// +// @PostMapping("/saveas") +// @ResponseBody +// public String saveAs(@RequestBody JSONObject body, @CookieValue("uid") String uid) { +// String title = (String) body.get("title"); +// String saveAsFileUrl = (String) body.get("url"); +// +// try { +// String fileName = documentManager.getCorrectName(title); +// String curExt = fileUtility.getFileExtension(fileName); +// +// if (!fileUtility.getFileExts().contains(curExt)) { +// return "{\"error\":\"File type is not supported\"}"; +// } +// +// URL url = new URL(saveAsFileUrl); +// java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection(); +// InputStream stream = connection.getInputStream(); +// +// if (Integer.parseInt(filesizeMax) < stream.available() || stream.available() <= 0) { +// return "{\"error\":\"File size is incorrect\"}"; +// } +// storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream); +// createUserMetadata(uid, fileName); +// +// return "{\"file\": \"" + fileName + "\"}"; +// } catch (IOException e) { +// e.printStackTrace(); +// return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}"; +// } +// } +// +// @PostMapping("/rename") +// @ResponseBody +// public String rename(@RequestBody JSONObject body) { +// String newfilename = (String) body.get("newfilename"); +// String dockey = (String) body.get("dockey"); +// String origExt = "." + (String) body.get("ext"); +// String curExt = newfilename; +// +// if(newfilename.indexOf(".") != -1) { +// curExt = (String) fileUtility.getFileExtension(newfilename); +// } +// +// if(origExt.compareTo(curExt) != 0) { +// newfilename += origExt; +// } +// +// HashMap meta = new HashMap<>(); +// meta.put("title", newfilename); +// +// try { +// callbackManager.commandRequest("meta", dockey, meta); +// return "result ok"; +// } catch (Exception e) { +// e.printStackTrace(); +// return e.getMessage(); +// } +// } +//} diff --git a/src/main/java/com/qiwenshare/file/office/controllers/IndexController.java b/src/main/java/com/qiwenshare/file/office/controllers/IndexController.java new file mode 100644 index 0000000..aa08088 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/controllers/IndexController.java @@ -0,0 +1,130 @@ +package com.qiwenshare.file.office.controllers;///** +// * +// * (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.office.controllers; +// +//import com.onlyoffice.integration.documentserver.storage.FileStorageMutator; +//import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder; +//import com.onlyoffice.integration.documentserver.util.Misc; +//import com.onlyoffice.integration.documentserver.util.file.FileUtility; +//import com.onlyoffice.integration.entities.*; +//import com.onlyoffice.integration.services.UserServices; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.stereotype.Controller; +//import org.springframework.ui.Model; +//import org.springframework.web.bind.annotation.CrossOrigin; +//import org.springframework.web.bind.annotation.GetMapping; +//import org.springframework.web.bind.annotation.PostMapping; +//import org.springframework.web.bind.annotation.ResponseBody; +// +//import java.util.*; +//import java.util.stream.Collectors; +// +//@CrossOrigin("*") +//@Controller +//public class IndexController { +// +// @Autowired +// private FileStorageMutator storageMutator; +// +// @Autowired +// private FileStoragePathBuilder storagePathBuilder; +// +// @Autowired +// private FileUtility fileUtility; +// +// @Autowired +// private Misc mistUtility; +// +// @Autowired +// private UserServices userService; +// +// @Value("${files.docservice.url.site}") +// private String docserviceSite; +// +// @Value("${files.docservice.url.preloader}") +// private String docservicePreloader; +// +// @Value("${url.converter}") +// private String urlConverter; +// +// @Value("${url.editor}") +// private String urlEditor; +// +// @Value("${files.docservice.languages}") +// private String langs; +// +// @GetMapping("${url.index}") +// public String index(Model model){ +// java.io.File[] files = storageMutator.getStoredFiles(); // get all the stored files from the storage +// List docTypes = new ArrayList<>(); +// List filesEditable = new ArrayList<>(); +// List versions = new ArrayList<>(); +// List isFillFormDoc = new ArrayList<>(); +// List langsAndKeys = Arrays.asList(langs.split("\\|")); +// +// Map languages = new LinkedHashMap<>(); +// +// langsAndKeys.forEach((str) -> { +// String[] couple = str.split(":"); +// languages.put(couple[0], couple[1]); +// }); +// +// List users = userService.findAll(); // get a list of all the users +// +// String tooltip = users.stream() // get the tooltip with the user descriptions +// .map(user -> mistUtility.convertUserDescriptions(user.getName(), user.getDescriptions())) // convert user descriptions to the specified format +// .collect(Collectors.joining()); +// +// for(java.io.File file:files){ // run through all the files +// String fileName = file.getName(); // get file name +// docTypes.add(fileUtility.getDocumentType(fileName).toString().toLowerCase()); // add a document type of each file to the list +// filesEditable.add(fileUtility.getEditedExts().contains(fileUtility.getFileExtension(fileName))); // specify if a file is editable or not +// versions.add(" ["+storagePathBuilder.getFileVersion(fileName, true)+"]"); // add a file version to the list +// isFillFormDoc.add(fileUtility.getFillExts().contains(fileUtility.getFileExtension(fileName))); +// } +// +// // add all the parameters to the model +// model.addAttribute("isFillFormDoc", isFillFormDoc); +// model.addAttribute("versions",versions); +// model.addAttribute("files", files); +// model.addAttribute("docTypes", docTypes); +// model.addAttribute("filesEditable", filesEditable); +// model.addAttribute("datadocs", docserviceSite+docservicePreloader); +// model.addAttribute("tooltip", tooltip); +// model.addAttribute("users", users); +// model.addAttribute("languages", languages); +// +// return "index.html"; +// } +// +// @PostMapping("/config") +// @ResponseBody +// public HashMap configParameters(){ // get configuration parameters +// HashMap configuration = new HashMap<>(); +// +// configuration.put("FillExtList", String.join(",", fileUtility.getFillExts())); // put a list of the extensions that can be filled to config +// configuration.put("ConverExtList", String.join(",", fileUtility.getConvertExts())); // put a list of the extensions that can be converted to config +// configuration.put("EditedExtList", String.join(",", fileUtility.getEditedExts())); // put a list of the extensions that can be edited to config +// configuration.put("UrlConverter", urlConverter); +// configuration.put("UrlEditor", urlEditor); +// +// return configuration; +// } +//} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/Callback.java b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/Callback.java new file mode 100644 index 0000000..3222562 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/Callback.java @@ -0,0 +1,32 @@ +/** + * + * (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.office.documentserver.callbacks; + +import com.qiwenshare.file.office.dto.Track; +import org.springframework.beans.factory.annotation.Autowired; + +// specify the callback handler functions +public interface Callback { + int handle(Track body, String fileName); // handle the callback + int getStatus(); // get document status + @Autowired + default void selfRegistration(CallbackHandler callbackHandler){ // register a callback handler + callbackHandler.register(getStatus(), this); + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/CallbackHandler.java b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/CallbackHandler.java new file mode 100644 index 0000000..ba8a21a --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/CallbackHandler.java @@ -0,0 +1,50 @@ +/** + * + * (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.office.documentserver.callbacks; + +import com.qiwenshare.file.office.dto.Track; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class CallbackHandler { + + private Logger logger = LoggerFactory.getLogger(CallbackHandler.class); + + private Map callbackHandlers = new HashMap<>(); + + public void register(int code, Callback callback){ // register a callback handler + callbackHandlers.put(code, callback); + } + + public int handle(Track body, String fileName){ // handle a callback + Callback callback = callbackHandlers.get(body.getStatus()); + if (callback == null){ + logger.warn("Callback status "+body.getStatus()+" is not supported yet"); + return 0; + } + + int result = callback.handle(body, fileName); + return result; + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/Status.java b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/Status.java new file mode 100644 index 0000000..e6cdc82 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/Status.java @@ -0,0 +1,35 @@ +/** + * + * (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.office.documentserver.callbacks; + +// document status +public enum Status { + EDITING(1), // 1 - document is being edited + SAVE(2), // 2 - document is ready for saving + CORRUPTED(3), // 3 - document saving error has occurred + MUST_FORCE_SAVE(6), // 6 - document is being edited, but the current document state is saved + CORRUPTED_FORCE_SAVE(7); // 7 - error has occurred while force saving the document + private int code; + Status(int code){ + this.code = code; + } + public int getCode(){ // get document status + return this.code; + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/EditCallback.java b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/EditCallback.java new file mode 100644 index 0000000..335562d --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/EditCallback.java @@ -0,0 +1,56 @@ +/** + * + * (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.office.documentserver.callbacks.implementations; + +import com.qiwenshare.file.office.documentserver.callbacks.Callback; +import com.qiwenshare.file.office.documentserver.callbacks.Status; +import com.qiwenshare.file.office.documentserver.managers.callback.CallbackManager; +import com.qiwenshare.file.office.dto.Action; +import com.qiwenshare.file.office.dto.Track; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class EditCallback implements Callback { + @Autowired + private CallbackManager callbackManager; + @Override + public int handle(Track body, String fileName) { // handle the callback when the document is being edited + int result = 0; + Action action = body.getActions().get(0); // get the user ID who is editing the document + if (action.getType().equals(com.qiwenshare.file.office.documentserver.models.enums.Action.edit)) { // if this value is not equal to the user ID + String user = action.getUserid(); // get user ID + if (!body.getUsers().contains(user)) { // if this user is not specified in the body + String key = body.getKey(); // get document key + try { + callbackManager.commandRequest("forcesave", key, null); // create a command request to forcibly save the document being edited without closing it + } catch (Exception e) { + e.printStackTrace(); + result = 1; + } + } + } + return result; + } + + @Override + public int getStatus() { // get document status + return Status.EDITING.getCode(); // return status 1 - document is being edited + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/ForcesaveCallback.java b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/ForcesaveCallback.java new file mode 100644 index 0000000..88f30f5 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/ForcesaveCallback.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.qiwenshare.file.office.documentserver.callbacks.implementations; + +import com.qiwenshare.file.office.documentserver.callbacks.Callback; +import com.qiwenshare.file.office.documentserver.callbacks.Status; +import com.qiwenshare.file.office.documentserver.managers.callback.CallbackManager; +import com.qiwenshare.file.office.dto.Track; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ForcesaveCallback implements Callback { + @Autowired + private CallbackManager callbackManager; + @Override + public int handle(Track body, String fileName) { // handle the callback when the force saving request is performed + int result = 0; + try { + callbackManager.processForceSave(body, fileName); // file force saving process + } catch (Exception ex) { + ex.printStackTrace(); + result = 1; + } + return result; + } + + @Override + public int getStatus() { // get document status + return Status.MUST_FORCE_SAVE.getCode(); // return status 6 - document is being edited, but the current document state is saved + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/SaveCallback.java b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/SaveCallback.java new file mode 100644 index 0000000..bb1e87f --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/callbacks/implementations/SaveCallback.java @@ -0,0 +1,49 @@ +/** + * + * (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.office.documentserver.callbacks.implementations; + +import com.qiwenshare.file.office.documentserver.callbacks.Callback; +import com.qiwenshare.file.office.documentserver.callbacks.Status; +import com.qiwenshare.file.office.documentserver.managers.callback.CallbackManager; +import com.qiwenshare.file.office.dto.Track; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class SaveCallback implements Callback { + @Autowired + private CallbackManager callbackManager; + @Override + public int handle(Track body, String fileName) { // handle the callback when the saving request is performed + int result = 0; + try { + callbackManager.processSave(body, fileName); // file saving process + } catch (Exception ex) { + ex.printStackTrace(); + result = 1; + } + + return result; + } + + @Override + public int getStatus() { // get document status + return Status.SAVE.getCode(); // return status 2 - document is ready for saving + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/callback/CallbackManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/callback/CallbackManager.java new file mode 100644 index 0000000..9483687 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/callback/CallbackManager.java @@ -0,0 +1,29 @@ +/** + * + * (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.office.documentserver.managers.callback; + +import com.qiwenshare.file.office.dto.Track; + +import java.util.HashMap; + +public interface CallbackManager { // specify the callback manager functions + void processSave(Track body, String fileName); // file saving process + void commandRequest(String method, String key, HashMap meta); // create a command request + void processForceSave(Track body, String fileName); // file force saving process +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/callback/DefaultCallbackManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/callback/DefaultCallbackManager.java new file mode 100644 index 0000000..41acc8e --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/callback/DefaultCallbackManager.java @@ -0,0 +1,280 @@ +/** + * + * (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.office.documentserver.managers.callback; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.qiwenshare.file.office.documentserver.managers.document.DocumentManager; +import com.qiwenshare.file.office.documentserver.managers.jwt.JwtManager; +import com.qiwenshare.file.office.documentserver.storage.FileStorageMutator; +import com.qiwenshare.file.office.documentserver.storage.FileStoragePathBuilder; +import com.qiwenshare.file.office.documentserver.util.file.FileUtility; +import com.qiwenshare.file.office.documentserver.util.service.ServiceConverter; +import com.qiwenshare.file.office.dto.Action; +import com.qiwenshare.file.office.dto.Track; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +//TODO: Refactoring +@Component +@Primary +public class DefaultCallbackManager implements CallbackManager { + + @Value("${files.docservice.url.site}") + private String docserviceUrlSite; + @Value("${files.docservice.url.command}") + private String docserviceUrlCommand; + @Value("${files.docservice.header}") + private String documentJwtHeader; + + @Autowired + private DocumentManager documentManager; + @Autowired + private JwtManager jwtManager; + @Autowired + private FileUtility fileUtility; + @Autowired + private FileStorageMutator storageMutator; + @Autowired + private FileStoragePathBuilder storagePathBuilder; +// @Autowired +// private ObjectMapper objectMapper; + @Autowired + private ServiceConverter serviceConverter; + + // save file information from the URL to the file specified + private void downloadToFile(String url, Path path) throws Exception { + if (url == null || url.isEmpty()) throw new RuntimeException("Url argument is not specified"); // URL isn't specified + if (path == null) throw new RuntimeException("Path argument is not specified"); // 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) { + connection.disconnect(); + throw new RuntimeException("Input stream is null"); + } + + storageMutator.createOrUpdateFile(path, stream); // update a file or create a new one + } + + @SneakyThrows + public void processSave(Track body, String fileName) { // file saving process + String downloadUri = body.getUrl(); + String changesUri = body.getChangesurl(); + String key = body.getKey(); + String newFileName = fileName; + + String curExt = fileUtility.getFileExtension(fileName); // get current file extension + String downloadExt = "." + body.getFiletype(); // get an extension of the downloaded file + + // Todo [Delete in version 7.0 or higher] + if (downloadExt != "." + null) downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0 + + //TODO: Refactoring + if (!curExt.equals(downloadExt)) { // convert downloaded file to the file with the current extension if these extensions aren't equal + try { + String newFileUri = serviceConverter.getConvertedUri(downloadUri, downloadExt, curExt, serviceConverter.generateRevisionId(downloadUri), null, false, null); // convert a file and get URL to a new file + if (newFileUri.isEmpty()) { + newFileName = documentManager + .getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt); // get the correct file name if it already exists + } else { + downloadUri = newFileUri; + } + } catch (Exception e){ + newFileName = documentManager.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt); + } + } + + String storagePath = storagePathBuilder.getFileLocation(newFileName); // get the path to a new file + Path lastVersion = Paths.get(storagePathBuilder.getFileLocation(fileName)); // get the path to the last file version + + if (lastVersion.toFile().exists()) { // if the last file version exists + Path histDir = Paths.get(storagePathBuilder.getHistoryDir(storagePath)); // get the history directory + storageMutator.createDirectory(histDir); // and create it + + String versionDir = documentManager.versionDir(histDir.toAbsolutePath().toString(), // get the file version directory + storagePathBuilder.getFileVersion(histDir.toAbsolutePath().toString(), false), true); + + Path ver = Paths.get(versionDir); + Path toSave = Paths.get(storagePath); + + storageMutator.createDirectory(ver); // create the file version directory + storageMutator.moveFile(lastVersion, Paths.get(versionDir + File.separator + "prev" + curExt)); // move the last file version to the file version directory with the "prev" postfix + + downloadToFile(downloadUri, toSave); // save file to the storage path + downloadToFile(changesUri, new File(versionDir + File.separator + "diff.zip").toPath()); // save file changes to the diff.zip archive + + JSONObject jsonChanges = new JSONObject(); // create a json object for document changes + jsonChanges.put("changes", body.getHistory().getChanges()); // put the changes to the json object + jsonChanges.put("serverVersion", body.getHistory().getServerVersion()); // put the server version to the json object +// String history = objectMapper.writeValueAsString(jsonChanges); + String history = JSON.toJSONString(jsonChanges); + if (history == null && body.getHistory() != null) { + history = JSON.toJSONString(body.getHistory()); + } + + if (history != null && !history.isEmpty()) { + storageMutator.writeToFile(versionDir + File.separator + "changes.json", history); // write the history changes to the changes.json file + } + + storageMutator.writeToFile(versionDir + File.separator + "key.txt", key); // write the key value to the key.txt file + storageMutator.deleteFile(storagePathBuilder.getForcesavePath(newFileName, false)); // get the path to the forcesaved file version and remove it + } + } + + //TODO: Replace (String method) with (Enum method) + @SneakyThrows + public void commandRequest(String method, String key, HashMap meta) { // create a command request + String DocumentCommandUrl = docserviceUrlSite + docserviceUrlCommand; + + 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); + + if (meta != null) { + params.put("meta", meta); + } + + String headerToken; + if (jwtManager.tokenEnabled()) // check if a secret key to generate token exists or not + { + Map payloadMap = new HashMap<>(); + payloadMap.put("payload", params); + headerToken = jwtManager.createToken(payloadMap); // encode a payload object into a header token + connection.setRequestProperty(documentJwtHeader.equals("") ? "Authorization" : documentJwtHeader, "Bearer " + headerToken); // add a header Authorization with a header token and Authorization prefix in it + + String token = jwtManager.createToken(params); // encode a payload object into a body token + params.put("token", token); + } + + String bodyString = JSON.toJSONString(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 RuntimeException("Could not get an answer"); + + String jsonString = serviceConverter.convertStreamToString(stream); // convert stream to json string + connection.disconnect(); + + JSONObject response = JSON.parseObject(jsonString); // convert json string to json object + //TODO: Add errors ENUM + String responseCode = response.get("error").toString(); + switch(responseCode) { + case "0": + case "4": { + break; + } + default: { + throw new RuntimeException(response.toJSONString()); + } + } + } + + @SneakyThrows + public void processForceSave(Track body, String fileName) { // file force saving process + + String downloadUri = body.getUrl(); + + String curExt = fileUtility.getFileExtension(fileName); // get current file extension + String downloadExt = "."+body.getFiletype(); // get an extension of the downloaded file + + // Todo [Delete in version 7.0 or higher] + if (downloadExt != "."+null) downloadExt = fileUtility.getFileExtension(downloadUri); // Support for versions below 7.0 + + Boolean newFileName = false; + + // convert downloaded file to the file with the current extension if these extensions aren't equal + //TODO: Extract function + 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 = ""; + + //TODO: Use ENUMS + //TODO: Pointless toString conversion + boolean isSubmitForm = body.getForcesavetype().toString().equals("3"); + + //TODO: Extract function + if (isSubmitForm) { // if the form is submitted + if (newFileName){ + fileName = documentManager + .getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "-form" + downloadExt); // get the correct file name if it already exists + } else { + fileName = documentManager.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + "-form" + curExt); + } + forcesavePath = storagePathBuilder.getFileLocation(fileName); // create forcesave path if it doesn't exist + List actions = body.getActions(); + Action action = actions.get(0); + String user = action.getUserid(); // get the user ID + storageMutator.createMeta(fileName, user, "Filling Form"); // create meta data for the forcesaved file + } else { + if (newFileName){ + fileName = documentManager.getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt); + } + + forcesavePath = storagePathBuilder.getForcesavePath(fileName, false); + if (forcesavePath.isEmpty()) { + forcesavePath = storagePathBuilder.getForcesavePath(fileName, true); + } + } + + downloadToFile(downloadUri, new File(forcesavePath).toPath()); + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/document/DefaultDocumentManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/document/DefaultDocumentManager.java new file mode 100644 index 0000000..dc76737 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/document/DefaultDocumentManager.java @@ -0,0 +1,234 @@ +/** + * + * (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.office.documentserver.managers.document; + +import com.qiwenshare.file.office.documentserver.storage.FileStorageMutator; +import com.qiwenshare.file.office.documentserver.storage.FileStoragePathBuilder; +import com.qiwenshare.file.office.documentserver.util.file.FileUtility; +import com.qiwenshare.file.office.documentserver.util.service.ServiceConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.InetAddress; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; + +@Component +@Primary +public class DefaultDocumentManager implements DocumentManager { + + @Value("${files.storage.folder}") + private String storageFolder; + @Value("${files.storage}") + private String filesStorage; + @Value("${url.track}") + private String trackUrl; + @Value("${url.download}") + private String downloadUrl; + + @Autowired + private FileStorageMutator storageMutator; + @Autowired + private FileStoragePathBuilder storagePathBuilder; + @Autowired + private FileUtility fileUtility; + @Autowired + private ServiceConverter serviceConverter; + @Autowired + private HttpServletRequest request; + + // get URL to the created file + public String getCreateUrl(String fileName, Boolean sample){ + String fileExt = fileName.substring(fileName.length() - 4); + String url = storagePathBuilder.getServerUrl(true) + "/create?fileExt=" + fileExt + "&sample=" + sample; + return url; + } + + // get a file name with an index if the file with such a name already exists + public String getCorrectName(String fileName) + { + String baseName = fileUtility.getFileNameWithoutExtension(fileName); // get file name without extension + String ext = fileUtility.getFileExtension(fileName); // get file extension + String name = baseName + ext; // create a full file name + + Path path = Paths.get(storagePathBuilder.getFileLocation(name)); + + for (int i = 1; Files.exists(path); 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 + path = Paths.get(storagePathBuilder.getFileLocation(name)); + } + + return name; + } + + // get file URL + public String getFileUri(String fileName, Boolean forDocumentServer) + { + try + { + String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL + String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory + String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName + : fileName.substring(fileName.indexOf(InetAddress.getLocalHost().getHostAddress()) + InetAddress.getLocalHost().getHostAddress().length() + 1); + if (!filesStorage.isEmpty() && filePathDownload.contains(filesStorage)) { + filePathDownload = filePathDownload.substring(filesStorage.length() + 1); + } + + String filePath = serverPath + "/download?fileName=" + URLEncoder.encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString()) + + "&userAddress" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()); + return filePath; + } + catch (UnsupportedEncodingException | UnknownHostException e) + { + return ""; + } + } + + // get file URL + public String getHistoryFileUrl(String fileName, Integer version, String file, Boolean forDocumentServer) + { + try + { + String serverPath = storagePathBuilder.getServerUrl(forDocumentServer); // get server URL + String hostAddress = storagePathBuilder.getStorageLocation(); // get the storage directory + String filePathDownload = !fileName.contains(InetAddress.getLocalHost().getHostAddress()) ? fileName + : fileName.substring(fileName.indexOf(InetAddress.getLocalHost().getHostAddress()) + InetAddress.getLocalHost().getHostAddress().length() + 1); + String userAddress = forDocumentServer ? "&userAddress" + URLEncoder.encode(hostAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : ""; + String filePath = serverPath + "/downloadhistory?fileName=" + URLEncoder.encode(filePathDownload, java.nio.charset.StandardCharsets.UTF_8.toString()) + + "&ver=" + version + "&file="+file + + userAddress; + return filePath; + } + catch (UnsupportedEncodingException | UnknownHostException e) + { + return ""; + } + } + + // get the callback URL + public String getCallback(String userFileId) + { + String serverPath = storagePathBuilder.getServerUrl(true); + + String query = "?type=edit&userFileId="+userFileId+"&token="+request.getHeader("token"); + + return serverPath + "/office/IndexServlet" + query; + + + } + + // get URL to download a file + public String getDownloadUrl(String fileName, Boolean isServer) { + String serverPath = storagePathBuilder.getServerUrl(isServer); + String storageAddress = storagePathBuilder.getStorageLocation(); + try + { + String userAddress = isServer ? "&userAddress=" + URLEncoder.encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : ""; + String query = downloadUrl+"?fileName=" + + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString()) + + userAddress; + + return serverPath + query; + } + catch (UnsupportedEncodingException e) + { + return ""; + } + } + + // get file information + public ArrayList> getFilesInfo(){ + ArrayList> files = new ArrayList<>(); + + // run through all the stored files + for(File file : storageMutator.getStoredFiles()){ + Map map = new LinkedHashMap<>(); // write all the parameters to the map + map.put("version", storagePathBuilder.getFileVersion(file.getName(), false)); + map.put("id", serviceConverter + .generateRevisionId(storagePathBuilder.getStorageLocation() + + "/" + file.getName() + "/" + + Paths.get(storagePathBuilder.getFileLocation(file.getName())) + .toFile() + .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 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 to the file version by the history path and file version + public String versionDir(String path, Integer version, boolean historyPath) { + if (!historyPath){ + return storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(path)) + version; + } + return path + File.separator + version; + } + + // create demo document +// public String createDemo(String fileExt,Boolean sample,String uid,String uname) { +// 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 + demoName; // get the path to the sample document +// String fileName = getCorrectName(demoName); // get a file name with an index if the file with such a name already exists +// +// InputStream stream = Thread.currentThread() +// .getContextClassLoader() +// .getResourceAsStream(demoPath); // get the input file stream +// +// if (stream == null) return null; +// +// storageMutator.createFile(Path.of(storagePathBuilder.getFileLocation(fileName)), stream); // create a file in the specified directory +// storageMutator.createMeta(fileName, uid, uname); // create meta information of the demo file +// +// return fileName; +// } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/document/DocumentManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/document/DocumentManager.java new file mode 100644 index 0000000..564ab09 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/document/DocumentManager.java @@ -0,0 +1,36 @@ +/** + * + * (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.office.documentserver.managers.document; + +import java.util.ArrayList; +import java.util.Map; + +// specify the document manager functions +public interface DocumentManager { + String getCorrectName(String fileName); // get a file name with an index if the file with such a name already exists + String getFileUri(String fileName, Boolean forDocumentServer); // get file URL + String getHistoryFileUrl(String fileName, Integer version, String file, Boolean forDocumentServer); // get file URL + String getCallback(String userFileId); // get the callback URL + String getDownloadUrl(String fileName, Boolean forDocumentServer); // get URL to download a file + ArrayList> getFilesInfo(); // get file information + ArrayList> getFilesInfo(String fileId); // get file information by its ID + String versionDir(String path, Integer version, boolean historyPath); // get the path to the file version by the history path and file version +// String createDemo(String fileExt,Boolean sample,String uid,String uname) throws Exception; // create demo document + String getCreateUrl(String fileName, Boolean sample); // get URL to the created file +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/history/DefaultHistoryManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/history/DefaultHistoryManager.java new file mode 100644 index 0000000..aa72e55 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/history/DefaultHistoryManager.java @@ -0,0 +1,157 @@ +/** + * (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.office.documentserver.managers.history; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.qiwenshare.file.office.documentserver.managers.document.DocumentManager; +import com.qiwenshare.file.office.documentserver.managers.jwt.JwtManager; +import com.qiwenshare.file.office.documentserver.models.filemodel.Document; +import com.qiwenshare.file.office.documentserver.storage.FileStoragePathBuilder; +import com.qiwenshare.file.office.documentserver.util.file.FileUtility; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.FileInputStream; +import java.util.*; + +//TODO: Rebuild completely +@Component +public class DefaultHistoryManager implements HistoryManager { + + @Autowired + private FileStoragePathBuilder storagePathBuilder; + + @Autowired + private DocumentManager documentManager; + + @Autowired + private JwtManager jwtManager; + + @Autowired + private FileUtility fileUtility; + +// @Autowired +// private JSONParser parser; + + @Autowired + private ObjectMapper objectMapper; + + //TODO: Refactoring + @SneakyThrows + public String[] getHistory(Document document) { // get document history + String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(document.getTitle())); // get history directory + Integer curVer = storagePathBuilder.getFileVersion(histDir, false); // get current file version + + if (curVer > 0) { // check if the current file version 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, true); // get the path to the given file version + + String key = i == curVer ? document.getKey() : readFileToEnd(new File(verDir + File.separator + "key.txt")); // get document key + 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 = JSON.parseObject(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("fileType", fileUtility.getFileExtension(document.getTitle()).replace(".", "")); + dataObj.put("key", key); + dataObj.put("url", i == curVer ? document.getUrl() : + documentManager.getHistoryFileUrl(document.getTitle(), i, "prev" + fileUtility.getFileExtension(document.getTitle()), true)); +// dataObj.put("directUrl", i == curVer ? document.getDirectUrl() : +// documentManager.getHistoryFileUrl(document.getTitle(), i, "prev" + fileUtility.getFileExtension(document.getTitle()), false)); + 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 = JSON.parseObject(readFileToEnd(new File(documentManager.versionDir(histDir, i - 1, true) + File.separator + "changes.json"))); + JSONObject change = (JSONObject) ((JSONArray) changes.get("changes")).get(0); + + // write information about changes to the object + 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 prev = (Map) histData.get(Integer.toString(i - 2)); // get the history data from the previous file version + Map prevInfo = new HashMap(); + prevInfo.put("fileType", prev.get("fileType")); + prevInfo.put("key", prev.get("key")); // write key and URL information about previous file version + prevInfo.put("url", prev.get("url")); + prevInfo.put("directUrl", prev.get("directUrl")); + 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 + Integer verdiff = i - 1; + dataObj.put("changesUrl", documentManager.getHistoryFileUrl(document.getTitle(), verdiff, "diff.zip", true)); + } + + if (jwtManager.tokenEnabled()) dataObj.put("token", jwtManager.createToken(dataObj)); + + hist.add(obj); + histData.put(Integer.toString(i - 1), dataObj); + } + + // write history information about the current file version to the history object + Map histObj = new HashMap(); + histObj.put("currentVersion", curVer); + histObj.put("history", hist); + + try { + return new String[]{objectMapper.writeValueAsString(histObj), objectMapper.writeValueAsString(histData)}; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + 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; + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/history/HistoryManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/history/HistoryManager.java new file mode 100644 index 0000000..78f165b --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/history/HistoryManager.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.qiwenshare.file.office.documentserver.managers.history; + +import com.qiwenshare.file.office.documentserver.models.filemodel.Document; + +// specify the history manager functions +public interface HistoryManager { + String[] getHistory(Document document); // get document history +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/jwt/DefaultJwtManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/jwt/DefaultJwtManager.java new file mode 100644 index 0000000..ee90848 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/jwt/DefaultJwtManager.java @@ -0,0 +1,120 @@ +/** + * + * (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.office.documentserver.managers.jwt; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; +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 org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.LinkedHashMap; +import java.util.Map; + +@Component +public class DefaultJwtManager implements JwtManager { + @Value("${files.docservice.secret}") + private String tokenSecret; + @Autowired + private ObjectMapper objectMapper; +// @Autowired +// private JSONParser parser; + + // create document token + public String createToken(Map payloadClaims) { + try { + // build a HMAC signer using a SHA-256 hash + Signer signer = HMACSigner.newSHA256Signer(tokenSecret); + 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 ""; + } + } + + // check if the token is enabled + public boolean tokenEnabled() { + return tokenSecret != null && !tokenSecret.isEmpty(); + } + + // read document token + public JWT readToken(String token) { + try { + // build a HMAC verifier using the token secret + Verifier verifier = HMACVerifier.newVerifier(tokenSecret); + return JWT.getDecoder().decode(token, verifier); // verify and decode the encoded string JWT to a rich object + } catch (Exception exception) { + return null; + } + } + + // parse the body + public JSONObject parseBody(String payload, String header) { + JSONObject body; + try { + body = JSON.parseObject(payload); // get body parameters by parsing the payload + } catch (Exception ex) { + throw new RuntimeException("{\"error\":1,\"message\":\"JSON Parsing error\"}"); + } + if (tokenEnabled()) { // check if the token is enabled + String token = (String) body.get("token"); // get token from the body + if (token == null) { // if token is empty + if (header != null && !StringUtils.isBlank(header)) { // and the header is defined + token = header.startsWith("Bearer ") ? header.substring(7) : header; // get token from the header (it is placed after the Bearer prefix if it exists) + } + } + if (token == null || StringUtils.isBlank(token)) { + throw new RuntimeException("{\"error\":1,\"message\":\"JWT expected\"}"); + } + + JWT jwt = readToken(token); // read token + if (jwt == null) { + throw new RuntimeException("{\"error\":1,\"message\":\"JWT validation failed\"}"); + } + LinkedHashMap claims = null; + if (jwt.getObject("payload") != null) { // get payload from the token and check if it is not empty + try { + @SuppressWarnings("unchecked") LinkedHashMap jwtPayload = + (LinkedHashMap)jwt.getObject("payload"); + + claims = jwtPayload; + } catch (Exception ex) { + throw new RuntimeException("{\"error\":1,\"message\":\"Wrong payload\"}"); + } + } + try { + body =JSON.parseObject(JSON.toJSONString(claims)); + } catch (Exception ex) { + throw new RuntimeException("{\"error\":1,\"message\":\"Parsing error\"}"); + } + } + + return body; + } +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/jwt/JwtManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/jwt/JwtManager.java new file mode 100644 index 0000000..5db11c6 --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/jwt/JwtManager.java @@ -0,0 +1,32 @@ +/** + * + * (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.office.documentserver.managers.jwt; + +import com.alibaba.fastjson2.JSONObject; +import org.primeframework.jwt.domain.JWT; + +import java.util.Map; + +// specify the jwt manager functions +public interface JwtManager { + boolean tokenEnabled(); // check if the token is enabled + String createToken(Map payloadClaims); // create document token + JWT readToken(String token); // read document token + JSONObject parseBody(String payload, String header); // parse the body +} diff --git a/src/main/java/com/qiwenshare/file/office/documentserver/managers/template/SampleTemplateManager.java b/src/main/java/com/qiwenshare/file/office/documentserver/managers/template/SampleTemplateManager.java new file mode 100644 index 0000000..7979a8d --- /dev/null +++ b/src/main/java/com/qiwenshare/file/office/documentserver/managers/template/SampleTemplateManager.java @@ -0,0 +1,67 @@ +/** + * + * (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.office.documentserver.managers.template; + +import com.qiwenshare.file.office.documentserver.managers.document.DocumentManager; +import com.qiwenshare.file.office.documentserver.models.enums.DocumentType; +import com.qiwenshare.file.office.documentserver.models.filemodel.Template; +import com.qiwenshare.file.office.documentserver.storage.FileStoragePathBuilder; +import com.qiwenshare.file.office.documentserver.util.file.FileUtility; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +@Qualifier("sample") +public class SampleTemplateManager implements TemplateManager { + @Autowired + private DocumentManager documentManager; + + @Autowired + private FileStoragePathBuilder storagePathBuilder; + + @Autowired + private FileUtility fileUtility; + + // create a template document with the specified name + public List