jiangbiao il y a 1 an
Parent
commit
9cd74d7bb5
99 fichiers modifiés avec 5973 ajouts et 59 suppressions
  1. 17 0
      admin/pom.xml
  2. 1 10
      admin/src/main/java/com/ruoyi/RuoYiApplication.java
  3. 85 0
      admin/src/main/java/com/ruoyi/project/office/OnlyofficeConfiguration.java
  4. 205 0
      admin/src/main/java/com/ruoyi/project/office/OnlyofficeController.java
  5. 32 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/Callback.java
  6. 50 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/CallbackHandler.java
  7. 35 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/Status.java
  8. 57 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/implementations/EditCallback.java
  9. 49 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/implementations/ForcesaveCallback.java
  10. 50 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/implementations/SaveCallback.java
  11. 30 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/callback/CallbackManager.java
  12. 281 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/callback/DefaultCallbackManager.java
  13. 219 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/document/DefaultDocumentManager.java
  14. 36 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/document/DocumentManager.java
  15. 158 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/history/DefaultHistoryManager.java
  16. 27 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/history/HistoryManager.java
  17. 121 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/jwt/DefaultJwtManager.java
  18. 32 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/jwt/JwtManager.java
  19. 68 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/template/SampleTemplateManager.java
  20. 30 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/managers/template/TemplateManager.java
  21. 24 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/AbstractModel.java
  22. 48 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Customization.java
  23. 36 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Embedded.java
  24. 44 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Goback.java
  25. 43 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Info.java
  26. 38 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Logo.java
  27. 31 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/Action.java
  28. 25 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/DocumentType.java
  29. 24 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/Mode.java
  30. 24 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/ToolbarDocked.java
  31. 25 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/Type.java
  32. 41 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/CommentGroup.java
  33. 42 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/Document.java
  34. 54 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/EditorConfig.java
  35. 41 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/FileModel.java
  36. 53 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/Permission.java
  37. 14 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/Template.java
  38. 43 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/User.java
  39. 23 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/serializers/FilterState.java
  40. 34 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/serializers/SerializerFilter.java
  41. 23 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/storage/FileStorageMutator.java
  42. 12 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/storage/FileStoragePathBuilder.java
  43. 361 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/storage/LocalFileStorage.java
  44. 16 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/util/Misc.java
  45. 54 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/util/SSLUtils.java
  46. 197 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/util/file/DefaultFileUtility.java
  47. 41 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/util/file/FileUtility.java
  48. 274 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/util/service/DefaultServiceConverter.java
  49. 31 0
      admin/src/main/java/com/ruoyi/project/office/documentserver/util/service/ServiceConverter.java
  50. 33 0
      admin/src/main/java/com/ruoyi/project/office/dto/Action.java
  51. 13 0
      admin/src/main/java/com/ruoyi/project/office/dto/ChangesHistory.java
  52. 13 0
      admin/src/main/java/com/ruoyi/project/office/dto/ChangesUser.java
  53. 40 0
      admin/src/main/java/com/ruoyi/project/office/dto/Convert.java
  54. 36 0
      admin/src/main/java/com/ruoyi/project/office/dto/Converter.java
  55. 40 0
      admin/src/main/java/com/ruoyi/project/office/dto/History.java
  56. 31 0
      admin/src/main/java/com/ruoyi/project/office/dto/Mentions.java
  57. 12 0
      admin/src/main/java/com/ruoyi/project/office/dto/PreviewOfficeFileDTO.java
  58. 46 0
      admin/src/main/java/com/ruoyi/project/office/dto/Track.java
  59. 35 0
      admin/src/main/java/com/ruoyi/project/office/entities/AbstractEntity.java
  60. 32 0
      admin/src/main/java/com/ruoyi/project/office/entities/Group.java
  61. 51 0
      admin/src/main/java/com/ruoyi/project/office/entities/Permission.java
  62. 50 0
      admin/src/main/java/com/ruoyi/project/office/entities/User.java
  63. 46 0
      admin/src/main/java/com/ruoyi/project/office/entities/UserFile.java
  64. 58 0
      admin/src/main/java/com/ruoyi/project/office/mappers/AbstractMapper.java
  65. 27 0
      admin/src/main/java/com/ruoyi/project/office/mappers/Mapper.java
  66. 57 0
      admin/src/main/java/com/ruoyi/project/office/mappers/PermissionsMapper.java
  67. 49 0
      admin/src/main/java/com/ruoyi/project/office/mappers/UsersMapper.java
  68. 27 0
      admin/src/main/java/com/ruoyi/project/office/repositories/GroupRepository.java
  69. 22 0
      admin/src/main/java/com/ruoyi/project/office/repositories/PermissionRepository.java
  70. 22 0
      admin/src/main/java/com/ruoyi/project/office/repositories/UserRepository.java
  71. 54 0
      admin/src/main/java/com/ruoyi/project/office/services/GroupServices.java
  72. 60 0
      admin/src/main/java/com/ruoyi/project/office/services/PermissionServices.java
  73. 82 0
      admin/src/main/java/com/ruoyi/project/office/services/UserServices.java
  74. 23 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/Configurer.java
  75. 25 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/CustomizationConfigurer.java
  76. 25 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/DocumentConfigurer.java
  77. 25 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/EditorConfigConfigurer.java
  78. 25 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/EmbeddedConfigurer.java
  79. 26 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/FileConfigurer.java
  80. 38 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultCustomizationConfigurer.java
  81. 67 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultDocumentConfigurer.java
  82. 105 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultEditorConfigConfigurer.java
  83. 47 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultEmbeddedConfigurer.java
  84. 138 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultFileConfigurer.java
  85. 31 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultCustomizationWrapper.java
  86. 33 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultDocumentWrapper.java
  87. 30 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultEmbeddedWrapper.java
  88. 40 0
      admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultFileWrapper.java
  89. 2 2
      admin/src/main/resources/application-druid.yml
  90. 37 4
      admin/src/main/resources/application.yml
  91. 1 1
      framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
  92. 1 1
      ui/package.json
  93. 19 0
      ui/src/api/onlyoffice/onlyoffice.js
  94. BIN
      ui/src/assets/images/profile.jpg
  95. 27 14
      ui/src/router/index.js
  96. 3 26
      ui/src/views/login.vue
  97. 198 0
      ui/src/views/onlyoffice/edit.vue
  98. 771 0
      ui/src/views/onlyoffice/index.vue
  99. 1 1
      ui/src/views/register.vue

+ 17 - 0
admin/pom.xml

@@ -60,6 +60,23 @@
             <groupId>com.newcpms</groupId>
             <artifactId>generator</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.22</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.inversoft</groupId>
+            <artifactId>prime-jwt</artifactId>
+            <version>1.3.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.modelmapper</groupId>
+            <artifactId>modelmapper</artifactId>
+            <version>2.4.2</version>
+        </dependency>
 
     </dependencies>
 

+ 1 - 10
admin/src/main/java/com/ruoyi/RuoYiApplication.java

@@ -16,15 +16,6 @@ public class RuoYiApplication
     {
         // System.setProperty("spring.devtools.restart.enabled", "false");
         SpringApplication.run(RuoYiApplication.class, args);
-        System.out.println("(♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙  \n" +
-                " .-------.       ____     __        \n" +
-                " |  _ _   \\      \\   \\   /  /    \n" +
-                " | ( ' )  |       \\  _. /  '       \n" +
-                " |(_ o _) /        _( )_ .'         \n" +
-                " | (_,_).' __  ___(_ o _)'          \n" +
-                " |  |\\ \\  |  ||   |(_,_)'         \n" +
-                " |  | \\ `'   /|   `-'  /           \n" +
-                " |  |  \\    /  \\      /           \n" +
-                " ''-'   `'-'    `-..-'              ");
+        System.out.println("(♥◠‿◠)ノ゙  cpms启动成功   ლ(´ڡ`ლ)゙");
     }
 }

+ 85 - 0
admin/src/main/java/com/ruoyi/project/office/OnlyofficeConfiguration.java

@@ -0,0 +1,85 @@
+/**
+ *
+ * (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.ruoyi.project.office;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.project.office.documentserver.storage.FileStoragePathBuilder;
+import com.ruoyi.project.office.documentserver.util.SSLUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.modelmapper.ModelMapper;
+import org.modelmapper.convention.MatchingStrategies;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+
+@Configuration
+public class OnlyofficeConfiguration {
+
+    @Value("${files.storage}")
+    private String storageAddress;
+
+    @Value("${files.docservice.verify-peer-off}")
+    private String verifyPerrOff;
+
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+
+    @Autowired
+    private SSLUtils ssl;
+
+    @Bean
+    public ModelMapper mapper(){  // create the model mapper
+        ModelMapper mapper = new ModelMapper();
+        mapper.getConfiguration()  // get the mapper configuration and set new parameters to it
+                .setMatchingStrategy(MatchingStrategies.STRICT)  // specify the STRICT matching strategy
+                .setFieldMatchingEnabled(true)  // define if the field matching is enabled or not
+                .setSkipNullEnabled(true)  // define if null value will be skipped or not
+                .setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE);  // specify the PRIVATE field access level
+        return mapper;
+    }
+
+//    @Bean
+//    public JSONParser jsonParser(){  // create JSON parser
+//        return new JSONParser();
+//    }
+
+    @PostConstruct
+    public void init(){  // initialize the storage path builder
+        storagePathBuilder.configure(StringUtils.isEmpty(storageAddress) ? null : storageAddress);
+        if(!verifyPerrOff.isEmpty()) {
+            try{
+                if(verifyPerrOff.equals("true")) {
+                    ssl.turnOffSslChecking(); //the certificate will be ignored
+                } else {
+                    ssl.turnOnSslChecking(); //the certificate will be verified
+                }
+            } catch(Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Bean
+    public ObjectMapper objectMapper(){  // create the object mapper
+        return new ObjectMapper();
+    }
+}

+ 205 - 0
admin/src/main/java/com/ruoyi/project/office/OnlyofficeController.java

@@ -0,0 +1,205 @@
+package com.ruoyi.project.office;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.project.office.documentserver.models.enums.Action;
+import com.ruoyi.project.office.documentserver.models.enums.Type;
+import com.ruoyi.project.office.documentserver.models.filemodel.FileModel;
+import com.ruoyi.project.office.dto.PreviewOfficeFileDTO;
+import com.ruoyi.project.office.entities.User;
+import com.ruoyi.project.office.entities.UserFile;
+import com.ruoyi.project.office.services.configurers.FileConfigurer;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultFileWrapper;
+import com.ruoyi.system.service.ISysUserService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Locale;
+
+
+@Component
+@RestController
+@RequestMapping(value = "/onlyoffice", method = RequestMethod.POST)
+public class OnlyofficeController extends BaseController {
+//
+//    protected final Logger logger = LoggerFactory.getLogger(BaseController.class);
+//    @Autowired
+//    private ISysUserService sysUserService;
+//
+//    @Autowired
+//    private FileConfigurer<DefaultFileWrapper> fileConfigurer;
+//
+//    @Value("${deployment.host}")
+//    private String deploymentHost;
+//    @Value("${server.port}")
+//    private String port;
+//
+//    @Value("${files.docservice.url.site}")
+//    private String docserviceSite;
+//
+//    @Value("${files.docservice.url.api}")
+//    private String docserviceApiUrl;
+//
+//    @Autowired
+//    private ITFileService tFileService;
+//
+//    @PostMapping("/previewFile")
+//    public AjaxResult preview(HttpServletRequest request, @RequestBody PreviewOfficeFileDTO previewOfficeFileDTO) {
+//        //获取当前用户
+//        SysUser sysUser = sysUserService.selectUserById(getUserId());
+//        Action action = Action.view;
+//        Type type = Type.desktop;
+//        Locale locale = new Locale("zh");
+//
+//        User user = new User(sysUser);
+//        //文件
+//        UserFile userFile = new UserFile();
+//        TFile rcfile = tFileService.selectTFileById(Long.parseLong(previewOfficeFileDTO.getUserFileId()));
+//        userFile.setFileId(rcfile.getId().toString());
+//        userFile.setFilePath(rcfile.getFileUrl());
+//        userFile.setFileName(rcfile.getFileName());
+//        userFile.setExtendName("");
+//        userFile.setUserFileId(rcfile.getId().toString());
+//        userFile.setUploadTime(String.valueOf(rcfile.getUploadDate().getTime()));
+//
+//        //下载地址
+//        String previewUrl = deploymentHost + rcfile.getFileUrl();
+////        String previewUrl = "/onlyoffice/download?filePath=" + rcfile.getFileUrl();
+//
+//
+//        FileModel fileModel = fileConfigurer.getFileModel(
+//                DefaultFileWrapper
+//                        .builder()
+//                        .userFile(userFile)
+//                        .type(type)
+//                        .lang(locale.toLanguageTag())
+//                        .action(action)
+//                        .user(user)
+//                        .actionData(previewUrl)
+//                        .build()
+//        );
+//        fileModel.setToken(null);
+//        JSONObject jsonObject = new JSONObject();
+//        jsonObject.put("file", fileModel);
+//        jsonObject.put("docserviceApiUrl", docserviceSite + docserviceApiUrl);
+//        jsonObject.put("reportName", userFile.getFileName());
+//        return AjaxResult.success(jsonObject);
+//    }
+//
+///*    @PostMapping("/editFile")
+//
+//    public AjaxResult edit(HttpServletRequest request,  @RequestBody PreviewOfficeFileDTO previewOfficeFileDTO) {
+//
+//        //
+//        SysUser sysUser = sysUserService.selectUserById(getUserId());
+//        Action action = Action.edit;
+//        Type type = Type.desktop;
+//        Locale locale = new Locale("zh");
+//
+//        User user = new User(sysUser);
+//        //文件
+//        UserFile userFile = new UserFile();
+//        TRcfile rcfile = tRcfileService.selectTRcfileById(Long.parseLong(previewOfficeFileDTO.getUserFileId()));
+//        userFile.setFileId(rcfile.getId().toString());
+//        userFile.setFilePath(rcfile.getFileUrl());
+//        userFile.setFileName(rcfile.getFileName());
+//        userFile.setExtendName("");
+//        userFile.setUserFileId(rcfile.getId().toString());
+//        userFile.setUploadTime(String.valueOf(rcfile.getUpdatedate().getTime()));
+//
+//        String previewUrl = "/onlyoffice/download?filePath=" + rcfile.getFileUrl();
+//
+//
+//        FileModel fileModel = fileConfigurer.getFileModel(
+//                DefaultFileWrapper
+//                        .builder()
+//                        .userFile(userFile)
+//                        .type(type)
+//                        .lang(locale.toLanguageTag())
+//                        .action(action)
+//                        .user(user)
+//                        .actionData(previewUrl)
+//                        .build()
+//        );
+//        fileModel.setToken(null);
+//        JSONObject jsonObject = new JSONObject();
+//        jsonObject.put("file",fileModel);
+//        jsonObject.put("docserviceApiUrl", docserviceSite + docserviceApiUrl);
+//        jsonObject.put("reportName",userFile.getFileName());
+//        return  AjaxResult.success(jsonObject);
+//    }
+//*/
+//
+///*    @RequestMapping(value = "/IndexServlet", method = RequestMethod.POST)
+//    @ResponseBody
+//    public void IndexServlet(HttpServletResponse response, HttpServletRequest request) throws IOException {
+//        logger.info(JSON.toJSONString(request.getParameterMap()));
+//        String token = request.getParameter("token");
+//
+//        PrintWriter writer = response.getWriter();
+//        Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");
+//        String body = scanner.hasNext() ? scanner.next() : "";
+//        JSONObject jsonObj = JSON.parseObject(body);
+//        logger.info(jsonObj.toJSONString());
+//        logger.info("===saveeditedfile:" + jsonObj.get("status"));
+//        String status = jsonObj != null ? jsonObj.get("status").toString() : "";
+//        if ("2".equals(status) || "6".equals(status)) {
+//            String type = request.getParameter("type");
+//            String downloadUri = (String) jsonObj.get("url");
+//            if("edit".equals(type)){ //修改报告
+//                String userFileId = request.getParameter("userFileId");
+//                TRcfile rcfile = tRcfileService.selectTRcfileById(Long.parseLong( userFileId ));
+//
+//                String pathForSave = RuoYiConfig.getProfile() + rcfile.getFileUrl().replace("/profile","");
+//                URL url = new URL(downloadUri);
+//                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+//
+//                InputStream stream = connection.getInputStream();
+//
+//                File savedFile = new File(pathForSave);
+//                try (FileOutputStream out = new FileOutputStream(savedFile)) {
+//                    int read;
+//                    final byte[] bytes = new byte[1024];
+//                    while ((read = stream.read(bytes)) != -1) {
+//                        out.write(bytes, 0, read);
+//                    }
+//                    out.flush();
+//                }
+//                connection.disconnect();
+//                //更新文件时间
+//                rcfile.setUpdatedate(new Date());
+//                tRcfileService.updateTRcfile(rcfile);
+//            }
+//        }
+//        writer.write("{\"error\":" + "0" + "}");
+//    }*/
+//
+//    /**
+//     *
+//     * @param response
+//     */
+///*    @GetMapping("/download")
+//    public void download(UserFile userFile, HttpServletResponse response) {
+//        try {
+//            String newFilePath = userFile.getFilePath().replace("/profile","");
+//            // 需要转换的文件路径
+//           String pathName = RuoYiConfig.getProfile()+newFilePath;
+//            logger.info("pathName::::::::::" + pathName);
+//            String fileName = pathName.substring(pathName.lastIndexOf("/") + 1);
+//            logger.info("fileName::::::::::" + fileName);
+//            FileUtils.downloadInline(pathName, fileName,response);
+//        }catch (Exception e){
+//            e.printStackTrace();
+//        }
+//
+//    }*/
+//
+
+}

+ 32 - 0
admin/src/main/java/com/ruoyi/project/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.ruoyi.project.office.documentserver.callbacks;
+
+import com.ruoyi.project.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);
+    }
+}

+ 50 - 0
admin/src/main/java/com/ruoyi/project/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.ruoyi.project.office.documentserver.callbacks;
+
+import com.ruoyi.project.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<Integer, Callback> 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;
+    }
+}

+ 35 - 0
admin/src/main/java/com/ruoyi/project/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.ruoyi.project.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;
+    }
+}

+ 57 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/implementations/EditCallback.java

@@ -0,0 +1,57 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.callbacks.implementations;
+
+
+import com.ruoyi.project.office.documentserver.callbacks.Callback;
+import com.ruoyi.project.office.documentserver.callbacks.Status;
+import com.ruoyi.project.office.documentserver.managers.callback.CallbackManager;
+import com.ruoyi.project.office.dto.Action;
+import com.ruoyi.project.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.ruoyi.project.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
+    }
+}

+ 49 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/implementations/ForcesaveCallback.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.ruoyi.project.office.documentserver.callbacks.implementations;
+
+
+import com.ruoyi.project.office.documentserver.callbacks.Callback;
+import com.ruoyi.project.office.documentserver.callbacks.Status;
+import com.ruoyi.project.office.documentserver.managers.callback.CallbackManager;
+import com.ruoyi.project.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
+    }
+}

+ 50 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/callbacks/implementations/SaveCallback.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.ruoyi.project.office.documentserver.callbacks.implementations;
+
+
+import com.ruoyi.project.office.documentserver.callbacks.Callback;
+import com.ruoyi.project.office.documentserver.callbacks.Status;
+import com.ruoyi.project.office.documentserver.managers.callback.CallbackManager;
+import com.ruoyi.project.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
+    }
+}

+ 30 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/callback/CallbackManager.java

@@ -0,0 +1,30 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.managers.callback;
+
+
+import com.ruoyi.project.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
+}

+ 281 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/callback/DefaultCallbackManager.java

@@ -0,0 +1,281 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.managers.callback;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.project.office.documentserver.managers.document.DocumentManager;
+import com.ruoyi.project.office.documentserver.managers.jwt.JwtManager;
+import com.ruoyi.project.office.documentserver.storage.FileStorageMutator;
+import com.ruoyi.project.office.documentserver.storage.FileStoragePathBuilder;
+import com.ruoyi.project.office.documentserver.util.file.FileUtility;
+import com.ruoyi.project.office.documentserver.util.service.ServiceConverter;
+import com.ruoyi.project.office.dto.Action;
+import com.ruoyi.project.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<String, Object> params = new HashMap<String, Object>();
+        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<String, Object> 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<Action> 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());
+    }
+}

+ 219 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/document/DefaultDocumentManager.java

@@ -0,0 +1,219 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.managers.document;
+
+
+import com.ruoyi.project.office.documentserver.storage.FileStorageMutator;
+import com.ruoyi.project.office.documentserver.storage.FileStoragePathBuilder;
+import com.ruoyi.project.office.documentserver.util.file.FileUtility;
+import com.ruoyi.project.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.annotation.Resource;
+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;
+
+    @Autowired
+    private FileStorageMutator storageMutator;
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+    @Autowired
+    private FileUtility fileUtility;
+    @Autowired
+    private ServiceConverter serviceConverter;
+    @Resource
+    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 + "/onlyoffice/IndexServlet" + query;
+
+
+    }
+
+    // get URL to download a file
+    public String getDownloadUrl(String fileName, Boolean isServer) {
+
+        return "";
+    }
+
+    // get file information
+    public ArrayList<Map<String, Object>> getFilesInfo(){
+        ArrayList<Map<String, Object>> files = new ArrayList<>();
+
+        // run through all the stored files
+        for(File file : storageMutator.getStoredFiles()){
+            Map<String, Object> 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<Map<String, Object>> getFilesInfo(String fileId){
+        ArrayList<Map<String, Object>> file = new ArrayList<>();
+
+        for (Map<String, Object> 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;
+//    }
+}

+ 36 - 0
admin/src/main/java/com/ruoyi/project/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.ruoyi.project.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<Map<String, Object>> getFilesInfo();  // get file information
+    ArrayList<Map<String, Object>> 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
+}

+ 158 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/history/DefaultHistoryManager.java

@@ -0,0 +1,158 @@
+/**
+ * (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.ruoyi.project.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.ruoyi.project.office.documentserver.managers.document.DocumentManager;
+import com.ruoyi.project.office.documentserver.managers.jwt.JwtManager;
+import com.ruoyi.project.office.documentserver.models.filemodel.Document;
+import com.ruoyi.project.office.documentserver.storage.FileStoragePathBuilder;
+import com.ruoyi.project.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<Object> hist = new ArrayList<>();
+            Map<String, Object> histData = new HashMap<>();
+
+            for (Integer i = 1; i <= curVer; i++) {  // run through all the file versions
+                Map<String, Object> obj = new HashMap<String, Object>();
+                Map<String, Object> dataObj = new HashMap<String, Object>();
+                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<String, Object> user = new HashMap<String, Object>();
+                    user.put("id", json.get("id"));
+                    user.put("name", json.get("name"));
+                    obj.put("user", user);
+                }
+
+                dataObj.put("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<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2));  // get the history data from the previous file version
+                    Map<String, Object> prevInfo = new HashMap<String, Object>();
+                    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<String, Object> histObj = new HashMap<String, Object>();
+            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;
+    }
+}

+ 27 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/history/HistoryManager.java

@@ -0,0 +1,27 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.managers.history;
+
+
+import com.ruoyi.project.office.documentserver.models.filemodel.Document;
+
+// specify the history manager functions
+public interface HistoryManager {
+    String[] getHistory(Document document);  // get document history
+}

+ 121 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/jwt/DefaultJwtManager.java

@@ -0,0 +1,121 @@
+/**
+ *
+ * (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.ruoyi.project.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<String, Object> 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<String, Object> claims = null;
+            if (jwt.getObject("payload") != null) {  // get payload from the token and check if it is not empty
+                try {
+                    @SuppressWarnings("unchecked") LinkedHashMap<String, Object> jwtPayload =
+                            (LinkedHashMap<String, Object>)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;
+    }
+}

+ 32 - 0
admin/src/main/java/com/ruoyi/project/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.ruoyi.project.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<String, Object> payloadClaims);  // create document token
+    JWT readToken(String token);  // read document token
+    JSONObject parseBody(String payload, String header);  // parse the body
+}

+ 68 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/template/SampleTemplateManager.java

@@ -0,0 +1,68 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.managers.template;
+
+
+import com.ruoyi.project.office.documentserver.managers.document.DocumentManager;
+import com.ruoyi.project.office.documentserver.models.enums.DocumentType;
+import com.ruoyi.project.office.documentserver.models.filemodel.Template;
+import com.ruoyi.project.office.documentserver.storage.FileStoragePathBuilder;
+import com.ruoyi.project.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<Template> createTemplates(String fileName){
+        List<Template> templates = new ArrayList<>();
+        templates.add(new Template("", "Blank", documentManager.getCreateUrl(fileName, false)));
+        templates.add(new Template(getTemplateImageUrl(fileName), "With sample content", documentManager.getCreateUrl(fileName, true)));
+
+        return templates;
+    }
+
+    // get the template image URL for the specified file
+    public String getTemplateImageUrl(String fileName){
+        DocumentType fileType = fileUtility.getDocumentType(fileName);  // get the file type
+        String path = storagePathBuilder.getServerUrl(true);  // get server URL
+        if(fileType.equals(DocumentType.word)){  // get URL to the template image for the word document type
+            return path + "/css/img/file_docx.svg";
+        } else if(fileType.equals(DocumentType.slide)){  // get URL to the template image for the slide document type
+            return path + "/css/img/file_pptx.svg";
+        } else if(fileType.equals(DocumentType.cell)){  // get URL to the template image for the cell document type
+            return path + "/css/img/file_xlsx.svg";
+        }
+        return path + "/css/img/file_docx.svg";  // get URL to the template image for the default document type (word)
+    }
+}

+ 30 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/managers/template/TemplateManager.java

@@ -0,0 +1,30 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.managers.template;
+
+
+import com.ruoyi.project.office.documentserver.models.filemodel.Template;
+
+import java.util.List;
+
+// specify the template manager functions
+public interface TemplateManager {
+    List<Template> createTemplates(String fileName);  // create a template document with the specified name
+    String getTemplateImageUrl(String fileName);  // get the template image URL for the specified file
+}

+ 24 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/AbstractModel.java

@@ -0,0 +1,24 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models;
+
+import java.io.Serializable;
+
+public abstract class AbstractModel implements Serializable {
+}

+ 48 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Customization.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.ruoyi.project.office.documentserver.models.configurations;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class Customization {  // the parameters which allow to customize the editor interface so that it looked like your other products (if there are any) and change the presence or absence of the additional buttons, links, change logos and editor owner details
+    @Autowired
+    private Logo logo;  // the image file at the top left corner of the Editor header
+    @Autowired
+    private Goback goback;  // the settings for the Open file location menu button and upper right corner button
+    private Boolean autosave = false;  // if the Autosave menu option is enabled or disabled
+    private Boolean comments = true;  // if the Comments menu button is displayed or hidden
+    private Boolean compactHeader = false;  // if the additional action buttons are displayed in the upper part of the editor window header next to the logo (false) or in the toolbar (true)
+    private Boolean compactToolbar = false;  // if the top toolbar type displayed is full (false) or compact (true)
+    private Boolean compatibleFeatures = false;  // the use of functionality only compatible with the OOXML format
+    private Boolean forcesave = false;  // add the request for the forced file saving to the callback handler when saving the document within the document editing service
+    private Boolean help = true;  //  if the Help menu button is displayed or hidden
+    private Boolean hideRightMenu = false;  // if the right menu is displayed or hidden on first loading
+    private Boolean hideRulers = false;  // if the editor rulers are displayed or hidden
+    private Boolean submitForm = false;  // if the Submit form button is displayed or hidden
+    private Boolean about = true;
+    private Boolean feedback =true;
+}

+ 36 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Embedded.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.ruoyi.project.office.documentserver.models.configurations;
+
+import com.ruoyi.project.office.documentserver.models.enums.ToolbarDocked;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class Embedded {  // the parameters which allow to change the settings which define the behavior of the buttons in the embedded mode
+    private String embedUrl;  // the absolute URL to the document serving as a source file for the document embedded into the web page
+    private String saveUrl;  // the absolute URL that will allow the document to be saved onto the user personal computer
+    private String shareUrl;  // the absolute URL that will allow other users to share this document
+    private ToolbarDocked toolbarDocked;  // the place for the embedded viewer toolbar, can be either top or bottom
+}

+ 44 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Goback.java

@@ -0,0 +1,44 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2021
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.ruoyi.project.office.documentserver.models.configurations;
+
+import com.ruoyi.project.office.documentserver.storage.FileStoragePathBuilder;
+import lombok.Getter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+@Component
+@Scope("prototype")
+public class Goback {  // the settings for the Open file location menu button and upper right corner button
+
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+
+
+    @Getter
+    private String url;  // the absolute URL to the website address which will be opened when clicking the Open file location menu button
+
+    @PostConstruct
+    private void init() {
+        this.url = storagePathBuilder.getServerUrl(false);
+    }
+}

+ 43 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Info.java

@@ -0,0 +1,43 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.configurations;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class Info {  // the additional parameters for the document (document owner, folder where the document is stored, uploading date, sharing settings)
+    private String owner = "Me";  // the name of the document owner/creator
+    private Boolean favorite = null;  // the highlighting state of the Favorite icon
+    private String uploaded = getDate();  // the document uploading date
+
+    private String getDate() {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE MMM dd yyyy", Locale.US);
+        return simpleDateFormat.format(new Date());
+    }
+}

+ 38 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/configurations/Logo.java

@@ -0,0 +1,38 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.configurations;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class Logo {  // the image file at the top left corner of the Editor header
+    @Value("${logo.image}")
+    private String image;  // the path to the image file used to show in common work mode
+    @Value("${logo.imageEmbedded}")
+    private String imageEmbedded;  // the path to the image file used to show in the embedded mode
+    @Value("${logo.url}")
+    private String url;  // the absolute URL which will be used when someone clicks the logo image
+}

+ 31 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/Action.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.enums;
+
+public enum Action {
+    edit,
+    review,
+    view,
+    embedded,
+    filter,
+    comment,
+    chat,
+    fillForms,
+    blockcontent
+}

+ 25 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/DocumentType.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.enums;
+
+public enum DocumentType {
+    word,
+    cell,
+    slide
+}

+ 24 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/Mode.java

@@ -0,0 +1,24 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.enums;
+
+public enum Mode {
+    edit,
+    view
+}

+ 24 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/ToolbarDocked.java

@@ -0,0 +1,24 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.enums;
+
+public enum ToolbarDocked {
+    top,
+    bottom
+}

+ 25 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/enums/Type.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.enums;
+
+public enum Type {
+    desktop,
+    mobile,
+    embedded
+}

+ 41 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/CommentGroup.java

@@ -0,0 +1,41 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.filemodel;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.ruoyi.project.office.documentserver.serializers.SerializerFilter;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CommentGroup {
+    @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
+    private List<String> view;  // define a list of groups whose comments the user can view
+    @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
+    private List<String> edit;  // define a list of groups whose comments the user can edit
+    @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
+    private List<String> remove;  // define a list of groups whose comments the user can remove
+}

+ 42 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/Document.java

@@ -0,0 +1,42 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.filemodel;
+
+import com.ruoyi.project.office.documentserver.models.configurations.Info;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class Document {  // the parameters pertaining to the document (title, url, file type, etc.)
+    @Autowired
+    private Info info;  // additional parameters for the document (document owner, folder where the document is stored, uploading date, sharing settings)
+    @Autowired
+    private Permission permissions;  // the permission for the document to be edited and downloaded or not
+    private String fileType;  //  the file type for the source viewed or edited document
+    private String key;  // the unique document identifier used by the service to recognize the document
+    private String title;  // the desired file name for the viewed or edited document which will also be used as file name when the document is downloaded
+    private String url;  // the absolute URL where the source viewed or edited document is stored
+
+}

+ 54 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/EditorConfig.java

@@ -0,0 +1,54 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.filemodel;
+
+
+import com.ruoyi.project.office.documentserver.models.configurations.Customization;
+import com.ruoyi.project.office.documentserver.models.configurations.Embedded;
+import com.ruoyi.project.office.documentserver.models.enums.Mode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+
+@Component
+@Scope("prototype")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class EditorConfig {  // the parameters pertaining to the editor interface: opening mode (viewer or editor), interface language, additional buttons, etc.
+    private HashMap<String, Object> actionLink = null;  // the data which contains the information about the action in the document that will be scrolled to
+    private String callbackUrl;  // the absolute URL to the document storage service
+    private HashMap<String, Object> coEditing = null;
+    private String createUrl;  // the absolute URL of the document where it will be created and available after creation
+    @Autowired
+    private Customization customization;  // the parameters which allow to customize the editor interface so that it looked like your other products (if there are any) and change the presence or absence of the additional buttons, links, change logos and editor owner details
+    @Autowired
+    private Embedded embedded;  // the parameters which allow to change the settings which define the behavior of the buttons in the embedded mode
+    private String lang;  // the editor interface language
+    private Mode mode;  // the editor opening mode
+    @Autowired
+    private User user;  // the user currently viewing or editing the document
+    private List<Template> templates;  // the presence or absence of the templates in the <b>Create New...</b> menu option
+}

+ 41 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/FileModel.java

@@ -0,0 +1,41 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.filemodel;
+
+import com.ruoyi.project.office.documentserver.models.enums.DocumentType;
+import com.ruoyi.project.office.documentserver.models.enums.Type;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class FileModel {  // the file base parameters which include the platform type used, document display size (width and height) and type of the document opened
+    @Autowired
+    private Document document;  // the parameters pertaining to the document (title, url, file type, etc.)
+    private DocumentType documentType;  // the document type to be opened
+    @Autowired
+    private EditorConfig editorConfig;  //  the parameters pertaining to the editor interface: opening mode (viewer or editor), interface language, additional buttons, etc.
+    private String token;  // the encrypted signature added to the Document Server config
+    private Type type;  // the platform type used to access the document
+}

+ 53 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/Permission.java

@@ -0,0 +1,53 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.filemodel;
+
+import com.ruoyi.project.office.documentserver.models.AbstractModel;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class Permission extends AbstractModel {  // the permission for the document to be edited and downloaded or not
+    private Boolean comment = true;  // if the document can be commented or not
+    private Boolean copy = true;  // if the content can be copied to the clipboard or not
+    private Boolean download = true;  // if the document can be downloaded or only viewed or edited online
+    private Boolean edit = true;  // if the document can be edited or only viewed
+    private Boolean print = true;  // if the document can be printed or not
+    private Boolean fillForms = true;  // if the forms can be filled
+    private Boolean modifyFilter = true;  // if the filter can applied globally (true) affecting all the other users, or locally (false)
+    private Boolean modifyContentControl = true;  // if the content control settings can be changed
+    private Boolean review = true;  // if the document can be reviewed or not
+    private Boolean chat = true;  // if a chat can be used
+//    private List<String> reviewGroups;  // the groups whose changes the user can accept/reject
+//    private CommentGroup commentGroups = new CommentGroup();  //  the groups whose comments the user can edit, remove and/or view
+    private Map commentGroups = new HashMap();
+
+    public Permission(){
+        commentGroups.put("aaa", "bbb");
+    }
+//    private List<String> userInfoGroups;
+}

+ 14 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/Template.java

@@ -0,0 +1,14 @@
+package com.ruoyi.project.office.documentserver.models.filemodel;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class Template {  // the document template parameters
+    private String image;  // the absolute URL to the image for template
+    private String title;  // the template title that will be displayed in the <b>Create New...</b> menu option
+    private String url;  // the absolute URL to the document where it will be created and available after creation
+}

+ 43 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/models/filemodel/User.java

@@ -0,0 +1,43 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.models.filemodel;
+
+import com.ruoyi.project.office.documentserver.models.AbstractModel;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class User extends AbstractModel {
+    private String id;
+    private String name;
+    private String group;
+
+
+    // the user configuration parameters
+    public void configure(int id, String name, String group){
+        this.id = "uid-"+id;  // the user id
+        this.name = name;  // the user name
+        this.group = group;  // the group the user belongs to
+    }
+}

+ 23 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/serializers/FilterState.java

@@ -0,0 +1,23 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.serializers;
+
+public enum FilterState {
+    NULL
+}

+ 34 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/serializers/SerializerFilter.java

@@ -0,0 +1,34 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.serializers;
+
+import java.util.List;
+
+public class SerializerFilter {
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof List) {
+            if(((List<?>) obj).size() == 1 && ((List<?>) obj).get(0) == FilterState.NULL.toString()){
+                return true;
+            }
+            return false;
+        }
+        return false;
+    }
+}

+ 23 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/storage/FileStorageMutator.java

@@ -0,0 +1,23 @@
+package com.ruoyi.project.office.documentserver.storage;
+
+import org.springframework.core.io.Resource;
+
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Path;
+
+// specify the file storage mutator functions
+public interface FileStorageMutator {
+    void createDirectory(Path path);  // create a new directory if it does not exist
+    boolean createFile(Path path, InputStream stream);  // create a new file if it does not exist
+    boolean deleteFile(String fileName);  // delete a file
+    boolean deleteFileHistory(String fileName);  // delete file history
+    String updateFile(String fileName, byte[] bytes);  // update a file
+    boolean writeToFile(String pathName, String payload);  // write the payload to the file
+    boolean moveFile(Path source, Path destination);  // move a file to the specified destination
+    Resource loadFileAsResource(String fileName);  // load file as a resource
+    Resource loadFileAsResourceHistory(String fileName,String version,String file);  // load file as a resource
+    File[] getStoredFiles();  // get a collection of all the stored files
+    void createMeta(String fileName, String uid, String uname);  // create the file meta information
+    boolean createOrUpdateFile(Path path, InputStream stream);  // create or update a file
+}

+ 12 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/storage/FileStoragePathBuilder.java

@@ -0,0 +1,12 @@
+package com.ruoyi.project.office.documentserver.storage;
+
+// specify the file storage path builder functions
+public interface FileStoragePathBuilder {
+    void configure(String address);  // create a new storage folder
+    String getStorageLocation();  // get the storage directory
+    String getFileLocation(String fileName);  // get the directory of the specified file
+    String getServerUrl(Boolean forDocumentServer);  // get the server URL
+    String getHistoryDir(String fileName);  // get the history directory
+    int getFileVersion(String historyPath, Boolean ifIndexPage);  // get the file version
+    String getForcesavePath(String fileName, Boolean create);  // get the path where all the forcely saved file versions are saved or create it
+}

+ 361 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/storage/LocalFileStorage.java

@@ -0,0 +1,361 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.storage;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.project.office.documentserver.util.file.FileUtility;
+import lombok.Getter;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.stereotype.Component;
+import org.springframework.util.FileSystemUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URLDecoder;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+//TODO: Refactoring
+@Component
+@Primary
+public class LocalFileStorage implements FileStorageMutator, FileStoragePathBuilder {
+
+    @Getter
+    private String storageAddress;
+
+    @Value("${files.storage.folder}")
+    private String storageFolder;
+
+    @Value("${files.docservice.url.example}")
+    private String docserviceUrlExample;
+
+    @Value("${files.docservice.history.postfix}")
+    private String historyPostfix;
+
+    @Autowired
+    private FileUtility fileUtility;
+    @Value("${deployment.host}")
+    private String deploymentHost;
+    @Value("${server.port}")
+    private String port;
+
+    @javax.annotation.Resource
+    private HttpServletRequest request;
+
+    /*
+        This Storage configuration method should be called whenever a new storage folder is required
+     */
+    public void configure(String address) {
+        this.storageAddress = address;
+        if(this.storageAddress == null){
+            try{
+                this.storageAddress = InetAddress.getLocalHost().getHostAddress();
+            } catch (UnknownHostException e){
+                this.storageAddress = "unknown_storage";
+            }
+        }
+        this.storageAddress.replaceAll("[^0-9a-zA-Z.=]", "_");
+        createDirectory(Paths.get(getStorageLocation()));
+    }
+
+    // get the storage directory
+    public String getStorageLocation(){
+        String serverPath = System.getProperty("user.dir");  // get the path to the server
+        String directory;  // create the storage directory
+        if (Paths.get(this.storageAddress).isAbsolute()) {
+            directory = this.storageAddress + File.separator;
+        } else {
+            directory = serverPath
+                    + File.separator + storageFolder
+                    + File.separator + this.storageAddress
+                    + File.separator;
+        }
+        if (!Files.exists(Paths.get(directory))) {
+            createDirectory(Paths.get(directory));
+        }
+
+        return directory;
+    }
+
+    // get the directory of the specified file
+    public String getFileLocation(String fileName){
+        if (fileName.contains(File.separator)) {
+            return getStorageLocation() + fileName;
+        }
+        return getStorageLocation() + fileUtility.getFileName(fileName);
+    }
+
+    // create a new directory if it does not exist
+    public void createDirectory(Path path){
+        if (Files.exists(path)) return;
+        try {
+            Files.createDirectories(path);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    // create a new file if it does not exist
+    public boolean createFile(Path path, InputStream stream){
+        if (Files.exists(path)){
+            return true;
+        }
+        try {
+            File file = Files.createFile(path).toFile();  // create a new file in the specified path
+            try (FileOutputStream out = new FileOutputStream(file))
+            {
+                int read;
+                final byte[] bytes = new byte[1024];
+                while ((read = stream.read(bytes)) != -1)
+                {
+                    out.write(bytes, 0, read);  // write bytes to the output stream
+                }
+                out.flush();  // force write data to the output stream that can be cached in the current thread
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    // delete a file
+    public boolean deleteFile(String fileName){
+        try {
+            fileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8.toString());  // decode a x-www-form-urlencoded string
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        if (StringUtils.isBlank(fileName)) return false;
+
+        String filenameWithoutExt = fileUtility.getFileNameWithoutExtension(fileName);  // get file name without extension
+
+        Path filePath = fileName.contains(File.separator) ? Paths.get(fileName) : Paths.get(getFileLocation(fileName));  // get the path to the file
+        Path filePathWithoutExt = fileName.contains(File.separator) ? Paths.get(filenameWithoutExt) : Paths.get(getStorageLocation() + filenameWithoutExt);  // get the path to the file without extension
+
+        boolean fileDeleted = FileSystemUtils.deleteRecursively(filePath.toFile());  // delete the specified file; for directories, recursively delete any nested directories or files as well
+        boolean fileWithoutExtDeleted = FileSystemUtils.deleteRecursively(filePathWithoutExt.toFile());  // delete the specified file without extension; for directories, recursively delete any nested directories or files as well
+
+        return fileDeleted && fileWithoutExtDeleted;
+    }
+
+    // delete file history
+    public boolean deleteFileHistory(String fileName) {
+        try {
+            fileName = URLDecoder.decode(fileName, StandardCharsets.UTF_8.toString());  // decode a x-www-form-urlencoded string
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        if (StringUtils.isBlank(fileName)) return false;
+
+        Path fileHistoryPath = Paths.get(getStorageLocation() + getHistoryDir(fileName));  // get the path to the history file
+        Path fileHistoryPathWithoutExt = Paths.get(getStorageLocation() + getHistoryDir(fileUtility.getFileNameWithoutExtension(fileName)));  // get the path to the history file without extension
+
+        boolean historyDeleted = FileSystemUtils.deleteRecursively(fileHistoryPath.toFile());  // delete the specified history file; for directories, recursively delete any nested directories or files as well
+        boolean historyWithoutExtDeleted = FileSystemUtils.deleteRecursively(fileHistoryPathWithoutExt.toFile());  // delete the specified history file without extension; for directories, recursively delete any nested directories or files as well
+
+        return historyDeleted || historyWithoutExtDeleted;
+    }
+
+    // update a file
+    public String updateFile(String fileName, byte[] bytes) {
+        Path path = fileUtility.generateFilepath(getStorageLocation(), fileName);  // generate the path to the specified file
+        try {
+            Files.write(path, bytes);  // write new information in the bytes format to the file
+            return path.getFileName().toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    // move a file to the specified destination
+    public boolean moveFile(Path source, Path destination){
+        try {
+            Files.move(source, destination,
+                    new StandardCopyOption[]{StandardCopyOption.REPLACE_EXISTING});
+            return true;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    // write the payload to the file
+    public boolean writeToFile(String pathName, String payload){
+        try (FileWriter fw = new FileWriter(pathName)) {
+            fw.write(payload);
+            return true;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    // get the path where all the forcely saved file versions are saved or create it
+    public String getForcesavePath(String fileName, Boolean create) {
+        String directory = getStorageLocation();
+
+        Path path = Paths.get(directory);  // get the storage directory
+        if (!Files.exists(path)) return "";
+
+        directory = getFileLocation(fileName) + historyPostfix + File.separator;
+
+        path = Paths.get(directory);   // get the history file directory
+        if (!create && !Files.exists(path)) return "";
+
+        createDirectory(path);  // create a new directory where all the forcely saved file versions will be saved
+
+        directory = directory + fileName;
+        path = Paths.get(directory);
+        if (!create && !Files.exists(path)) {
+            return "";
+        }
+
+        return directory;
+    }
+
+    // load file as a resource
+    public Resource loadFileAsResource(String fileName){
+        String fileLocation = getForcesavePath(fileName, false);  // get the path where all the forcely saved file versions are saved
+        if (StringUtils.isBlank(fileLocation)){  // if file location is empty
+            fileLocation = getFileLocation(fileName);  // get it by the file name
+        }
+        try {
+            Path filePath = Paths.get(fileLocation);  // get the path to the file location
+            Resource resource = new UrlResource(filePath.toUri());  // convert the file path to URL
+            if(resource.exists()) return resource;
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public Resource loadFileAsResourceHistory(String fileName,String version,String file){
+
+        String fileLocation = getStorageLocation() + fileName + "-hist" + File.separator + version + File.separator + file;  // get it by the file name
+
+        try {
+            Path filePath = Paths.get(fileLocation);  // get the path to the file location
+            Resource resource = new UrlResource(filePath.toUri());  // convert the file path to URL
+            if(resource.exists()) return resource;
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    // get a collection of all the stored files
+    public File[] getStoredFiles()
+    {
+        File file = new File(getStorageLocation());
+        return file.listFiles(pathname -> pathname.isFile());
+    }
+
+    @SneakyThrows
+    public void createMeta(String fileName, String uid, String uname) {  // create the file meta information
+        String histDir = getHistoryDir(getFileLocation(fileName));  // get the history directory
+
+        Path path = Paths.get(histDir);  // get the path to the history directory
+        createDirectory(path);  // create the history directory
+
+        // create the json object with the file metadata
+        JSONObject json = new JSONObject();
+        json.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));  // put the file creation date to the json object
+        json.put("id", uid);  // put the user ID to the json object
+        json.put("name", uname);  // put the user name to the json object
+
+        File meta = new File(histDir + File.separator + "createdInfo.json");  // create the createdInfo.json file with the file meta information
+        try (FileWriter writer = new FileWriter(meta)) {
+            writer.append(json.toJSONString());
+        } catch (IOException ex){
+            ex.printStackTrace();
+        }
+    }
+
+    // create or update a file
+    public boolean createOrUpdateFile(Path path, InputStream stream) {
+//        if (!Files.exists(path)){ // if the specified file does not exist
+//            return createFile(path, stream);  // create it in the specified directory
+//        } else {
+//            try {
+//                Files.write(path, stream.readAllBytes());  // otherwise, write new information in the bytes format to the file
+//                return true;
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//            }
+//        }
+        return false;
+    }
+
+    // get the server URL
+    public String getServerUrl(Boolean forDocumentServer) {
+        if (forDocumentServer && !docserviceUrlExample.equals("")) {
+            return docserviceUrlExample;
+        } else {
+            return request.getScheme()+"://"+ deploymentHost + request.getContextPath();
+//            return request.getScheme()+"://"+ deploymentHost + ":" + port + request.getContextPath();
+//            return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
+        }
+    }
+
+    // get the history directory
+    public String getHistoryDir(String path)
+    {
+        return path + historyPostfix;
+    }
+
+    // get the file version
+    public int getFileVersion(String historyPath, Boolean ifIndexPage)
+    {
+        Path path;
+        if (ifIndexPage) {  // if the start page is opened
+            path = Paths.get(getStorageLocation() + getHistoryDir(historyPath));  // get the storage directory and add the history directory to it
+        } else {
+            path = Paths.get(historyPath);  // otherwise, get the path to the history directory
+            if (!Files.exists(path)) return 1;  // if the history directory does not exist, then the file version is 1
+        }
+
+        try (Stream<Path> stream = Files.walk(path, 1)) {  // run through all the files in the history directory
+            return stream
+                    .filter(file -> Files.isDirectory(file))  // take only directories from the history folder
+                    .map(Path::getFileName)  // get file names
+                    .map(Path::toString)  // and convert them into strings
+                    .collect(Collectors.toSet()).size();  // convert stream into set and get its size which specifies the file version
+        } catch (IOException e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+}

+ 16 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/util/Misc.java

@@ -0,0 +1,16 @@
+package com.ruoyi.project.office.documentserver.util;
+
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Component
+public class Misc {
+    public String convertUserDescriptions(String username, List<String> description){  // cenvert user descriptions to the specified format
+        String result = "<div class=\"user-descr\"><b>"+username+"</b><br/><ul>"+description.
+                stream().map(text -> "<li>"+text+"</li>")
+                .collect(Collectors.joining()) + "</ul></div>";
+        return result;
+    }
+}

+ 54 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/util/SSLUtils.java

@@ -0,0 +1,54 @@
+package com.ruoyi.project.office.documentserver.util;
+
+import org.springframework.stereotype.Component;
+
+import javax.net.ssl.*;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Disables and enables certificate and host-name checking in
+ * HttpsURLConnection, the default JVM implementation of the HTTPS/TLS protocol.
+ * Has no effect on implementations such as Apache Http Client, Ok Http.
+*/
+@Component
+public final class SSLUtils {
+
+    private final HostnameVerifier jvmHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
+
+    private final HostnameVerifier trivialHostnameVerifier = new HostnameVerifier() {
+        public boolean verify(String hostname, SSLSession sslSession) {
+            return true;
+        }
+    };
+
+    private final TrustManager[] UNQUESTIONING_TRUST_MANAGER = new TrustManager[] { new X509TrustManager() {
+        public X509Certificate[] getAcceptedIssuers() {
+            return null;
+        }
+
+        public void checkClientTrusted(X509Certificate[] certs, String authType) {
+        }
+
+        public void checkServerTrusted(X509Certificate[] certs, String authType) {
+        }
+    } };
+
+    public void turnOffSslChecking() throws NoSuchAlgorithmException, KeyManagementException {
+        HttpsURLConnection.setDefaultHostnameVerifier(trivialHostnameVerifier);
+        // Install the all-trusting trust manager
+        SSLContext sc = SSLContext.getInstance("SSL");
+        sc.init(null, UNQUESTIONING_TRUST_MANAGER, null);
+        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+    }
+
+    public void turnOnSslChecking() throws KeyManagementException, NoSuchAlgorithmException {
+        HttpsURLConnection.setDefaultHostnameVerifier(jvmHostnameVerifier);
+        // Return it to the initial state (discovered by reflection, now hardcoded)
+        SSLContext sc = SSLContext.getInstance("SSL");
+        sc.init(null, null, null);
+        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+    }
+
+}

+ 197 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/util/file/DefaultFileUtility.java

@@ -0,0 +1,197 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.util.file;
+
+import com.ruoyi.project.office.documentserver.models.enums.DocumentType;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@Component
+@Qualifier("default")
+public class DefaultFileUtility implements FileUtility {
+    @Value("${filesize-max}")
+    private String filesizeMax;
+
+    @Value("${files.docservice.viewed-docs}")
+    private String docserviceViewedDocs;
+
+    @Value("${files.docservice.edited-docs}")
+    private String docserviceEditedDocs;
+
+    @Value("${files.docservice.convert-docs}")
+    private String docserviceConvertDocs;
+
+    @Value("${files.docservice.fillforms-docs}")
+    private String docserviceFillDocs;
+
+    // document extensions
+    private List<String> ExtsDocument = Arrays.asList(
+                            ".doc", ".docx", ".docm",
+                            ".dot", ".dotx", ".dotm",
+                            ".odt", ".fodt", ".ott", ".rtf", ".txt",
+                            ".html", ".htm", ".mht", ".xml",
+                            ".pdf", ".djvu", ".fb2", ".epub", ".xps", ".oform");
+
+    // spreadsheet extensions
+    private List<String> ExtsSpreadsheet = Arrays.asList(
+                            ".xls", ".xlsx", ".xlsm", ".xlsb",
+                            ".xlt", ".xltx", ".xltm",
+                            ".ods", ".fods", ".ots", ".csv");
+
+    // presentation extensions
+    private List<String> ExtsPresentation = Arrays.asList(
+                            ".pps", ".ppsx", ".ppsm",
+                            ".ppt", ".pptx", ".pptm",
+                            ".pot", ".potx", ".potm",
+                            ".odp", ".fodp", ".otp");
+
+    // get the document type
+    public DocumentType getDocumentType(String fileName)
+    {
+        System.out.println("System.out.println(fileName);" + fileName);
+        String ext = getFileExtension(fileName).toLowerCase();  // get file extension from its name
+        System.out.println(ext);
+        // word type for document extensions
+        if (ExtsDocument.contains(ext))
+            return DocumentType.word;
+
+        // cell type for spreadsheet extensions
+        if (ExtsSpreadsheet.contains(ext))
+            return DocumentType.cell;
+
+        // slide type for presentation extensions
+        if (ExtsPresentation.contains(ext))
+            return DocumentType.slide;
+
+        // default file type is word
+        return DocumentType.word;
+    }
+
+    // get file name from its URL
+    public String getFileName(String url)
+    {
+        if (url == null) return "";
+
+        // get file name from the last part of URL
+        String fileName = url.substring(url.lastIndexOf('/') + 1);
+        fileName = fileName.split("\\?")[0];
+        return fileName;
+    }
+
+    // get file name without extension
+    public String getFileNameWithoutExtension(String url)
+    {
+        String fileName = getFileName(url);
+        if (fileName == null) return null;
+        String fileNameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.'));
+        return fileNameWithoutExt;
+    }
+
+    // get file extension from URL
+    public String getFileExtension(String url)
+    {
+        String fileName = getFileName(url);
+        if (fileName == null) return null;
+        String fileExt = fileName.substring(fileName.lastIndexOf("."));
+        return fileExt.toLowerCase();
+    }
+
+    // get an editor internal extension
+    public String getInternalExtension(DocumentType type)
+    {
+        // .docx for word file type
+        if (type.equals(DocumentType.word))
+            return ".docx";
+
+        // .xlsx for cell file type
+        if (type.equals(DocumentType.cell))
+            return ".xlsx";
+
+        // .pptx for slide file type
+        if (type.equals(DocumentType.slide))
+            return ".pptx";
+
+        // the default file type is .docx
+        return ".docx";
+    }
+
+    public List<String> getFillExts()
+    {
+        return Arrays.asList(docserviceFillDocs.split("\\|"));
+    }
+
+    // get file extensions that can be viewed
+    public List<String> getViewedExts()
+    {
+        return Arrays.asList(docserviceViewedDocs.split("\\|"));
+    }
+
+    // get file extensions that can be edited
+    public List<String> getEditedExts()
+    {
+        return Arrays.asList(docserviceEditedDocs.split("\\|"));
+    }
+
+    // get file extensions that can be converted
+    public List<String> getConvertExts()
+    {
+        return Arrays.asList(docserviceConvertDocs.split("\\|"));
+    }
+
+    // get all the supported file extensions
+    public List<String> getFileExts() {
+        List<String> res = new ArrayList<>();
+
+        res.addAll(getViewedExts());
+        res.addAll(getEditedExts());
+        res.addAll(getConvertExts());
+        res.addAll(getFillExts());
+
+        return res;
+    }
+
+    // generate the file path from file directory and name
+    public Path generateFilepath(String directory, String fullFileName){
+        String fileName = getFileNameWithoutExtension(fullFileName);  // get file name without extension
+        String fileExtension = getFileExtension(fullFileName);  // get file extension
+        Path path = Paths.get(directory+fullFileName);  // get the path to the files with the specified name
+
+        for(int i = 1; Files.exists(path); i++){  // run through all the files with the specified name
+            fileName = getFileNameWithoutExtension(fullFileName) + "("+i+")";  // get a name of each file without extension and add an index to it
+            path = Paths.get(directory+fileName+fileExtension);  // create a new path for this file with the correct name and extension
+        }
+
+        path = Paths.get(directory+fileName+fileExtension);
+        return path;
+    }
+
+    // get maximum file size
+    public long getMaxFileSize(){
+        long size = Long.parseLong(filesizeMax);
+        return size > 0 ? size : 5 * 1024 * 1024;
+    }
+}

+ 41 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/util/file/FileUtility.java

@@ -0,0 +1,41 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.util.file;
+
+
+import com.ruoyi.project.office.documentserver.models.enums.DocumentType;
+
+import java.nio.file.Path;
+import java.util.List;
+
+// specify the file utility functions
+public interface FileUtility {
+    DocumentType getDocumentType(String fileName);  // get the document type
+    String getFileName(String url);  // get file name from its URL
+    String getFileNameWithoutExtension(String url);  // get file name without extension
+    String getFileExtension(String url);  // get file extension from URL
+    String getInternalExtension(DocumentType type);  // get an editor internal extension
+    List<String> getFileExts();  // get all the supported file extensions
+    List<String> getFillExts();  // get file extensions that can be filled
+    List<String> getViewedExts();  // get file extensions that can be viewed
+    List<String> getEditedExts();  // get file extensions that can be edited
+    List<String> getConvertExts();  // get file extensions that can be converted
+    Path generateFilepath(String directory, String fullFileName);  // generate the file path from file directory and name
+    long getMaxFileSize();  // get maximum file size
+}

+ 274 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/util/service/DefaultServiceConverter.java

@@ -0,0 +1,274 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.util.service;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.project.office.documentserver.managers.jwt.JwtManager;
+import com.ruoyi.project.office.documentserver.util.file.FileUtility;
+import com.ruoyi.project.office.dto.Convert;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+//TODO: Refactoring
+@Component
+public class DefaultServiceConverter implements ServiceConverter
+{
+    @Value("${files.docservice.header}")
+    private String documentJwtHeader;
+    @Value("${files.docservice.url.site}")
+    private String docServiceUrl;
+    @Value("${files.docservice.url.converter}")
+    private String docServiceUrlConverter;
+    @Value("${files.docservice.timeout}")
+    private String docserviceTimeout;
+    private int convertTimeout = 120000;
+
+    @Autowired
+    private JwtManager jwtManager;
+    @Autowired
+    private FileUtility fileUtility;
+//    @Autowired
+//    private JSONParser parser;
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @PostConstruct
+    public void init(){
+        int timeout = Integer.parseInt(docserviceTimeout);  // parse the dcoument service timeout value
+        if (timeout > 0) convertTimeout = timeout;
+    }
+
+    @SneakyThrows
+    private String postToServer(Convert body, String headerToken){  // send the POST request to the server
+        String bodyString = objectMapper.writeValueAsString(body);  // write the body request to the object mapper in the string format
+        URL url = null;
+        java.net.HttpURLConnection connection = null;
+        InputStream response = null;
+        String jsonString = null;
+
+        byte[] bodyByte = bodyString.getBytes(StandardCharsets.UTF_8);  // convert body string into bytes
+        try{
+            // set the request parameters
+            url = new URL(docServiceUrl+docServiceUrlConverter);
+            connection = (java.net.HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("POST");
+            connection.setDoOutput(true);
+            connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
+            connection.setFixedLengthStreamingMode(bodyByte.length);
+            connection.setRequestProperty("Accept", "application/json");
+            connection.setConnectTimeout(convertTimeout);
+
+            // check if the token is enabled
+            if (jwtManager.tokenEnabled())
+            {
+                // set the JWT header to the request
+                connection.setRequestProperty(StringUtils.isBlank(documentJwtHeader) ?
+                        "Authorization" : documentJwtHeader, "Bearer " + headerToken);
+            }
+
+            connection.connect();
+            try (OutputStream os = connection.getOutputStream()) {
+                os.write(bodyByte);  // write bytes to the output stream
+                os.flush();  // force write data to the output stream that can be cached in the current thread
+            }
+
+            response = connection.getInputStream();  // get the input stream
+            jsonString = convertStreamToString(response);  // convert the response stream into a string
+        } finally {
+            connection.disconnect();
+            return jsonString;
+        }
+    }
+
+    // get the URL to the converted file
+    public String getConvertedUri(String documentUri, String fromExtension,
+                                  String toExtension, String documentRevisionId,
+                                  String filePass, Boolean isAsync, String lang)
+    {
+        // check if the fromExtension parameter is defined; if not, get it from the document url
+        fromExtension = fromExtension == null || fromExtension.isEmpty() ?
+                fileUtility.getFileExtension(documentUri) : fromExtension;
+
+        // check if the file name parameter is defined; if not, get random uuid for this file
+        String title = fileUtility.getFileName(documentUri);
+        title = title == null || title.isEmpty() ? UUID.randomUUID().toString() : title;
+
+        documentRevisionId = documentRevisionId == null || documentRevisionId.isEmpty() ? documentUri : documentRevisionId;
+
+        documentRevisionId = generateRevisionId(documentRevisionId);  // create document token
+
+        // write all the necessary parameters to the body object
+        Convert body = new Convert();
+        body.setLang(lang);
+        body.setUrl(documentUri);
+        body.setOutputtype(toExtension.replace(".", ""));
+        body.setFiletype(fromExtension.replace(".", ""));
+        body.setTitle(title);
+        body.setKey(documentRevisionId);
+        body.setFilePass(filePass);
+        if (isAsync)
+            body.setAsync(true);
+
+        String headerToken = "";
+        if (jwtManager.tokenEnabled())
+        {
+            HashMap<String, Object> map = new HashMap<String, Object>();
+            map.put("region", lang);
+            map.put("url", body.getUrl());
+            map.put("outputtype", body.getOutputtype());
+            map.put("filetype", body.getFiletype());
+            map.put("title", body.getTitle());
+            map.put("key", body.getKey());
+            map.put("password", body.getFilePass());
+            if (isAsync)
+                map.put("async", body.getAsync());
+
+            // add token to the body if it is enabled
+            String token = jwtManager.createToken(map);
+            body.setToken(token);
+
+            Map<String, Object> payloadMap = new HashMap<String, Object>();
+            payloadMap.put("payload", map);  // create payload object
+            headerToken = jwtManager.createToken(payloadMap);  // create header token
+        }
+
+        String jsonString = postToServer(body, headerToken);
+
+        return getResponseUri(jsonString);
+    }
+
+    // generate document key
+    public String generateRevisionId(String expectedKey)
+    {
+        if (expectedKey.length() > 20)  // if the expected key length is greater than 20
+            expectedKey = Integer.toString(expectedKey.hashCode());  // the expected key is hashed and a fixed length value is stored in the string format
+
+        String key = expectedKey.replace("[^0-9-.a-zA-Z_=]", "_");
+
+        return key.substring(0, Math.min(key.length(), 20));  // the resulting key length is 20 or less
+    }
+
+    //TODO: Replace with a registry (callbacks package for reference)
+    private void processConvertServiceResponceError(int errorCode)  // create an error message for an error code
+    {
+        String errorMessage = "";
+        String errorMessageTemplate = "Error occurred in the ConvertService: ";
+
+        // add the error message to the error message template depending on the error code
+        switch (errorCode)
+        {
+            case -8:
+                errorMessage = errorMessageTemplate + "Error document VKey";
+                break;
+            case -7:
+                errorMessage = errorMessageTemplate + "Error document request";
+                break;
+            case -6:
+                errorMessage = errorMessageTemplate + "Error database";
+                break;
+            case -5:
+                errorMessage = errorMessageTemplate + "Error unexpected guid";
+                break;
+            case -4:
+                errorMessage = errorMessageTemplate + "Error download error";
+                break;
+            case -3:
+                errorMessage = errorMessageTemplate + "Error convertation error";
+                break;
+            case -2:
+                errorMessage = errorMessageTemplate + "Error convertation timeout";
+                break;
+            case -1:
+                errorMessage = errorMessageTemplate + "Error convertation unknown";
+                break;
+            case 0:  // if the error code is equal to 0, the error message is empty
+                break;
+            default:
+                errorMessage = "ErrorCode = " + errorCode;  // default value for the error message
+                break;
+        }
+
+        throw new RuntimeException(errorMessage);
+    }
+
+    @SneakyThrows
+    private String getResponseUri(String jsonString)  // get the response URL
+    {
+//        JSONObject jsonObj = convertStringToJSON(jsonString);
+        JSONObject jsonObj = JSON.parseObject(jsonString);
+        Object error = jsonObj.get("error");
+        if (error != null)  // if an error occurs
+            processConvertServiceResponceError(Math.toIntExact((long)error));  // then get an error message
+
+        // check if the conversion is completed and save the result to a variable
+        Boolean isEndConvert = (Boolean) jsonObj.get("endConvert");
+
+        Long resultPercent = 0l;
+        String responseUri = null;
+
+        if (isEndConvert)  // if the conversion is completed
+        {
+            resultPercent = 100l;
+            responseUri = (String) jsonObj.get("fileUrl");  // get the file URL
+        }
+        else  // if the conversion isn't completed
+        {
+            resultPercent = (Long) jsonObj.get("percent");
+            resultPercent = resultPercent >= 100l ? 99l : resultPercent;  // get the percentage value of the conversion process
+        }
+
+        return resultPercent >= 100l ? responseUri : "";
+    }
+
+    @SneakyThrows
+    public String convertStreamToString(InputStream stream)  // convert stream to string
+    {
+        InputStreamReader inputStreamReader = new InputStreamReader(stream);  // create an object to get incoming stream
+        StringBuilder stringBuilder = new StringBuilder();  // create a string builder object
+        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  // create an object to read incoming streams
+        String line = bufferedReader.readLine();  // get incoming streams by lines
+
+        while (line != null)
+        {
+            stringBuilder.append(line);  // concatenate strings using the string builder
+            line = bufferedReader.readLine();
+        }
+
+        String result = stringBuilder.toString();
+
+        return result;
+    }
+
+}

+ 31 - 0
admin/src/main/java/com/ruoyi/project/office/documentserver/util/service/ServiceConverter.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (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.ruoyi.project.office.documentserver.util.service;
+
+import java.io.InputStream;
+
+
+// specify the converter service functions
+public interface ServiceConverter {
+    String getConvertedUri(String documentUri, String fromExtension,  // get the URL to the converted file
+                                  String toExtension, String documentRevisionId,
+                                  String filePass, Boolean isAsync, String lang);
+    String generateRevisionId(String expectedKey);  // generate document key
+    String convertStreamToString(InputStream stream);  // convert stream to string
+}

+ 33 - 0
admin/src/main/java/com/ruoyi/project/office/dto/Action.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (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.ruoyi.project.office.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Action {
+    private String userid;
+    private com.ruoyi.project.office.documentserver.models.enums.Action type;
+}

+ 13 - 0
admin/src/main/java/com/ruoyi/project/office/dto/ChangesHistory.java

@@ -0,0 +1,13 @@
+package com.ruoyi.project.office.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ChangesHistory {
+    private String created;
+    private ChangesUser user;
+}

+ 13 - 0
admin/src/main/java/com/ruoyi/project/office/dto/ChangesUser.java

@@ -0,0 +1,13 @@
+package com.ruoyi.project.office.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ChangesUser {
+    private String id;
+    private String name;
+}

+ 40 - 0
admin/src/main/java/com/ruoyi/project/office/dto/Convert.java

@@ -0,0 +1,40 @@
+/**
+ *
+ * (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.ruoyi.project.office.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Convert {
+    private String url;
+    private String outputtype;
+    private String filetype;
+    private String title;
+    private String key;
+    private String filePass;
+    private Boolean async;
+    private String token;
+    private String lang;
+}

+ 36 - 0
admin/src/main/java/com/ruoyi/project/office/dto/Converter.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.ruoyi.project.office.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class Converter {
+    @JsonProperty("filename")
+    private String fileName;
+    @JsonProperty("filePass")
+    private String filePass;
+    @JsonProperty("lang")
+    private String lang;
+}

+ 40 - 0
admin/src/main/java/com/ruoyi/project/office/dto/History.java

@@ -0,0 +1,40 @@
+/**
+ *
+ * (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.ruoyi.project.office.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ruoyi.project.office.documentserver.models.filemodel.User;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class History {
+    @JsonProperty("serverVersion")
+    private String serverVersion;
+    private String key;
+    private Integer version;
+    private String created;
+    private User user;
+    private List<ChangesHistory> changes;
+}

+ 31 - 0
admin/src/main/java/com/ruoyi/project/office/dto/Mentions.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (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.ruoyi.project.office.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class Mentions {
+    private String name;
+    private String email;
+}

+ 12 - 0
admin/src/main/java/com/ruoyi/project/office/dto/PreviewOfficeFileDTO.java

@@ -0,0 +1,12 @@
+package com.ruoyi.project.office.dto;
+
+import lombok.Data;
+
+@Data
+public class PreviewOfficeFileDTO {
+   private String userFileId;
+   private String previewUrl;
+//   private String filePath;
+//   private String fileName;
+//   private String extendName;
+}

+ 46 - 0
admin/src/main/java/com/ruoyi/project/office/dto/Track.java

@@ -0,0 +1,46 @@
+/**
+ *
+ * (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.ruoyi.project.office.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Track {
+    private String filetype;
+    private String url;
+    private String key;
+    private String changesurl;
+    private History history;
+    private String token;
+    private Integer forcesavetype;
+    private Integer status;
+    private List<String> users;
+    private List<Action> actions;
+    private String userdata;
+    private String lastsave;
+    private Boolean notmodified;
+}

+ 35 - 0
admin/src/main/java/com/ruoyi/project/office/entities/AbstractEntity.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.ruoyi.project.office.entities;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Setter
+@Getter
+public abstract class AbstractEntity implements Serializable {
+
+    String id;
+}

+ 32 - 0
admin/src/main/java/com/ruoyi/project/office/entities/Group.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.ruoyi.project.office.entities;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+
+@Getter
+@Setter
+public class Group extends AbstractEntity {
+    private String name;
+    private List<User> users;
+}

+ 51 - 0
admin/src/main/java/com/ruoyi/project/office/entities/Permission.java

@@ -0,0 +1,51 @@
+/**
+ *
+ * (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.ruoyi.project.office.entities;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+
+@Getter
+@Setter
+public class Permission extends AbstractEntity {
+    private Boolean comment = true;
+    private Boolean copy = true;
+    private Boolean download = true;
+    private Boolean edit = true;
+    private Boolean print = true;
+    private Boolean fillForms = true;
+    private Boolean modifyFilter = true;
+    private Boolean modifyContentControl = true;
+    private Boolean review = true;
+    private Boolean chat = true;
+    private Boolean templates=true;
+//    @ManyToMany
+    private List<Group> reviewGroups;
+//    @ManyToMany
+    private List<Group> commentsViewGroups;
+//    @ManyToMany
+    private List<Group> commentsEditGroups;
+//    @ManyToMany
+    private List<Group> commentsRemoveGroups;
+//    @ManyToMany
+    private List<Group> userInfoGroups;
+}

+ 50 - 0
admin/src/main/java/com/ruoyi/project/office/entities/User.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.ruoyi.project.office.entities;
+
+import com.ruoyi.common.core.domain.entity.SysUser;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class User extends AbstractEntity {
+    private String name;
+    private String email;
+    private Boolean favorite;
+//    @ManyToOne
+    private String group;
+//    @OneToOne
+    private Permission permissions;
+//    @Column(columnDefinition = "CLOB")
+//    @ElementCollection
+//    @CollectionTable(name = "user_descriptions")
+    private List<String> descriptions;
+
+    public User(){}
+
+    public User(SysUser userBean) {
+        this.id = String.valueOf(userBean.getUserId());
+        this.name = userBean.getNickName();
+        this.group = "";
+
+    }
+}

+ 46 - 0
admin/src/main/java/com/ruoyi/project/office/entities/UserFile.java

@@ -0,0 +1,46 @@
+package com.ruoyi.project.office.entities;
+
+import lombok.Data;
+
+
+@Data
+public class UserFile {
+
+    private String userFileId;
+
+    private String userId;
+
+    private String fileId;
+
+    private String fileName;
+
+    private String filePath;
+
+    private String extendName;
+
+    private Integer isDir;
+
+    private String uploadTime;
+
+    private Integer deleteFlag;
+
+    private String deleteTime;
+
+    private String deleteBatchNum;
+    private String createTime;
+    private String createUserId;
+    private String modifyTime;
+    private String modifyUserId;
+
+    public UserFile() {};
+
+
+    public boolean isDirectory() {
+        return this.isDir == 1;
+    }
+
+    public boolean isFile() {
+        return this.isDir == 0;
+    }
+
+}

+ 58 - 0
admin/src/main/java/com/ruoyi/project/office/mappers/AbstractMapper.java

@@ -0,0 +1,58 @@
+/**
+ *
+ * (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.ruoyi.project.office.mappers;
+
+import com.ruoyi.project.office.documentserver.models.AbstractModel;
+import com.ruoyi.project.office.entities.AbstractEntity;
+import org.modelmapper.Converter;
+import org.modelmapper.ModelMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.Objects;
+
+public abstract class AbstractMapper<E extends AbstractEntity, M extends AbstractModel> implements Mapper<E, M> {
+    @Autowired
+    ModelMapper mapper;
+
+    private Class<M> modelClass;
+
+    AbstractMapper(Class<M> modelClass) {
+        this.modelClass = modelClass;
+    }
+
+    @Override
+    public M toModel(E entity) {  // convert the entity to the model
+        return Objects.isNull(entity)  // check if an entity is not empty
+                ? null
+                : mapper.map(entity, modelClass);  // and add it to the model mapper
+    }
+
+    Converter<E, M> modelConverter() {  // specify the model converter
+        return context -> {
+            E source = context.getSource();  // get the source entity
+            M destination = context.getDestination();  // get the destination model
+            handleSpecificFields(source, destination);  // map the entity to the model
+            return context.getDestination();
+        };
+    }
+
+
+    void handleSpecificFields(E source, M destination) {
+    }
+}

+ 27 - 0
admin/src/main/java/com/ruoyi/project/office/mappers/Mapper.java

@@ -0,0 +1,27 @@
+/**
+ *
+ * (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.ruoyi.project.office.mappers;
+
+import com.ruoyi.project.office.documentserver.models.AbstractModel;
+import com.ruoyi.project.office.entities.AbstractEntity;
+
+// specify the model mapper functions
+public interface Mapper<E extends AbstractEntity, M extends AbstractModel> {
+   M toModel(E entity);  // convert the entity to the model
+}

+ 57 - 0
admin/src/main/java/com/ruoyi/project/office/mappers/PermissionsMapper.java

@@ -0,0 +1,57 @@
+/**
+ *
+ * (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.ruoyi.project.office.mappers;
+
+import com.ruoyi.project.office.entities.Permission;
+import org.modelmapper.ModelMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+@Component
+@Primary
+public class PermissionsMapper extends AbstractMapper<Permission, com.ruoyi.project.office.documentserver.models.filemodel.Permission> {
+    @Autowired
+    private ModelMapper mapper;
+
+    public PermissionsMapper() {
+        super(com.ruoyi.project.office.documentserver.models.filemodel.Permission.class);
+    }
+
+    @PostConstruct
+    public void configure() {  // configure the permission mapper
+        mapper.createTypeMap(Permission.class, com.ruoyi.project.office.documentserver.models.filemodel.Permission.class)  // create the type map
+                .setPostConverter(modelConverter());  // and apply the post converter to it
+    }
+
+    @Override
+    void handleSpecificFields(Permission source, com.ruoyi.project.office.documentserver.models.filemodel.Permission destination) {  // handle specific permission fields
+//        destination.setReviewGroups(source.getReviewGroups().stream().map(g -> g.getName()).collect(Collectors.toList()));  // set the reviewGroups parameter
+//        destination.setCommentGroups(  // set the commentGroups parameter
+//                new CommentGroup(
+//                        source.getCommentsViewGroups().stream().map(g -> g.getName()).collect(Collectors.toList()),
+//                        source.getCommentsEditGroups().stream().map(g -> g.getName()).collect(Collectors.toList()),
+//                        source.getCommentsRemoveGroups().stream().map(g -> g.getName()).collect(Collectors.toList())
+//                )
+//        );
+//        destination.setUserInfoGroups(source.getUserInfoGroups().stream().map(g -> g.getName()).collect(Collectors.toList()));
+    }
+}

+ 49 - 0
admin/src/main/java/com/ruoyi/project/office/mappers/UsersMapper.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.ruoyi.project.office.mappers;
+
+import com.ruoyi.project.office.entities.User;
+import org.modelmapper.ModelMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+@Component
+@Primary
+public class UsersMapper extends AbstractMapper<User, com.ruoyi.project.office.documentserver.models.filemodel.User> {
+    @Autowired
+    private ModelMapper mapper;
+
+    public UsersMapper(){
+        super(com.ruoyi.project.office.documentserver.models.filemodel.User.class);
+    }
+
+    @PostConstruct
+    public void configure() {  // configure the users mapper
+        mapper.createTypeMap(User.class, com.ruoyi.project.office.documentserver.models.filemodel.User.class)  // create the type map
+                .setPostConverter(modelConverter());  // and apply the post converter to it
+    }
+
+    @Override
+    public void handleSpecificFields(User source, com.ruoyi.project.office.documentserver.models.filemodel.User destination) {  // handle specific users fields
+//        destination.setGroup(source.getGroup() != null ? source.getGroup().getName() : null);  // set the Group parameter
+    }
+}

+ 27 - 0
admin/src/main/java/com/ruoyi/project/office/repositories/GroupRepository.java

@@ -0,0 +1,27 @@
+/**
+ *
+ * (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.ruoyi.project.office.repositories;
+
+import com.ruoyi.project.office.entities.Group;
+
+import java.util.Optional;
+
+public interface GroupRepository {
+    Optional<Group> findGroupByName(String name);
+}

+ 22 - 0
admin/src/main/java/com/ruoyi/project/office/repositories/PermissionRepository.java

@@ -0,0 +1,22 @@
+/**
+ *
+ * (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.ruoyi.project.office.repositories;
+
+public interface PermissionRepository {
+}

+ 22 - 0
admin/src/main/java/com/ruoyi/project/office/repositories/UserRepository.java

@@ -0,0 +1,22 @@
+/**
+ *
+ * (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.ruoyi.project.office.repositories;
+
+public interface UserRepository {
+}

+ 54 - 0
admin/src/main/java/com/ruoyi/project/office/services/GroupServices.java

@@ -0,0 +1,54 @@
+/**
+ *
+ * (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.ruoyi.project.office.services;
+
+import com.ruoyi.project.office.entities.Group;
+import com.ruoyi.project.office.repositories.GroupRepository;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+//@Service
+public class GroupServices {
+
+//    @Autowired
+    private GroupRepository groupRepository;
+
+    // create a new group with the specified name
+    public Group createGroup(String name){
+        if(name == null) return null;  // check if a name is specified
+        Optional<Group> group = groupRepository.findGroupByName(name);  // check if group with such a name already exists
+        if(group.isPresent()) return group.get();  // if it exists, return it
+        Group newGroup = new Group();
+        newGroup.setName(name);  // otherwise, create a new group with the specified name
+
+//        groupRepository.save(newGroup);  // save a new group
+
+        return newGroup;
+    }
+
+    // create a list of groups from the reviewGroups permission parameter
+    public List<Group> createGroups(List<String> reviewGroups){
+        if(reviewGroups == null) return null;  // check if the reviewGroups permission exists
+        return reviewGroups.stream()  // convert this parameter to a list of groups whose changes the user can accept/reject
+                .map(group -> createGroup(group))
+                .collect(Collectors.toList());
+    }
+}

+ 60 - 0
admin/src/main/java/com/ruoyi/project/office/services/PermissionServices.java

@@ -0,0 +1,60 @@
+/**
+ *
+ * (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.ruoyi.project.office.services;
+
+import com.ruoyi.project.office.entities.Group;
+import com.ruoyi.project.office.entities.Permission;
+import com.ruoyi.project.office.repositories.PermissionRepository;
+
+import java.util.List;
+
+//@Service
+public class PermissionServices {
+
+//    @Autowired
+    private PermissionRepository permissionRepository;
+
+    // create permissions with the specified parameters
+    public Permission createPermission(List<Group> reviewGroups,
+                                       List<Group> commentViewGroups,
+                                       List<Group> commentEditGroups,
+                                       List<Group> commentRemoveGroups,
+                                       List<Group> userInfoGroups,
+                                       Boolean chat){
+
+        Permission permission = new Permission();
+        permission.setReviewGroups(reviewGroups);  // define the groups whose changes the user can accept/reject
+        permission.setCommentsViewGroups(commentViewGroups);  // defines the groups whose comments the user can view
+        permission.setCommentsEditGroups(commentEditGroups);  // defines the groups whose comments the user can edit
+        permission.setCommentsRemoveGroups(commentRemoveGroups);  // defines the groups whose comments the user can remove
+        permission.setUserInfoGroups(userInfoGroups);
+        permission.setChat(chat);
+
+//        permissionRepository.save(permission);  // save new permissions
+
+        return permission;
+    }
+
+    // update permissions
+    public Permission updatePermission(Permission newPermission){
+//        permissionRepository.save(newPermission);  // save new permissions
+
+        return newPermission;
+    }
+}

+ 82 - 0
admin/src/main/java/com/ruoyi/project/office/services/UserServices.java

@@ -0,0 +1,82 @@
+/**
+ *
+ * (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.ruoyi.project.office.services;
+
+import com.ruoyi.project.office.entities.Group;
+import com.ruoyi.project.office.entities.Permission;
+import com.ruoyi.project.office.entities.User;
+import com.ruoyi.project.office.repositories.UserRepository;
+
+import java.util.List;
+import java.util.Optional;
+
+//@Service
+public class UserServices {
+//    @Autowired
+    private UserRepository userRepository;
+
+//    @Autowired
+    private GroupServices groupServices;
+
+//    @Autowired
+    private PermissionServices permissionService;
+
+    // get a list of all users
+    public List<User> findAll(){
+//        return userRepository.findAll();
+        return null;
+    }
+
+    // get a user by their ID
+    public Optional<User> findUserById(Integer id){
+//        return userRepository.findById(id);
+        return null;
+    }
+
+    // create a user with the specified parameters
+    public User createUser(String name, String email,
+                           List<String> description, String group,
+                           List<String> reviewGroups,
+                           List<String> viewGroups,
+                           List<String> editGroups,
+                           List<String> removeGroups,
+                           List<String> userInfoGroups, Boolean favoriteDoc,
+                           Boolean chat){
+        User newUser = new User();
+        newUser.setName(name);  // set the user name
+        newUser.setEmail(email);  // set the user email
+//        newUser.setGroup(groupServices.createGroup(group));  // set the user group
+        newUser.setDescriptions(description);  // set the user description
+        newUser.setFavorite(favoriteDoc);  // specify if the user has the favorite documents or not
+
+        List<Group> groupsReview = groupServices.createGroups(reviewGroups);  // define the groups whose changes the user can accept/reject
+        List<Group> commentGroupsView = groupServices.createGroups(viewGroups);  // defines the groups whose comments the user can view
+        List<Group> commentGroupsEdit = groupServices.createGroups(editGroups);  // defines the groups whose comments the user can edit
+        List<Group> commentGroupsRemove = groupServices.createGroups(removeGroups);  // defines the groups whose comments the user can remove
+        List<Group> usInfoGroups = groupServices.createGroups(userInfoGroups);
+
+        Permission permission = permissionService
+                .createPermission(groupsReview, commentGroupsView, commentGroupsEdit, commentGroupsRemove, usInfoGroups, chat);  // specify permissions for the current user
+        newUser.setPermissions(permission);
+
+//        userRepository.save(newUser); // save a new user
+
+        return newUser;
+    }
+}

+ 23 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/Configurer.java

@@ -0,0 +1,23 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers;
+
+public interface Configurer<O, W> {
+    void configure(O instance, W wrapper);
+}

+ 25 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/CustomizationConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers;
+
+import com.ruoyi.project.office.documentserver.models.configurations.Customization;
+
+public interface CustomizationConfigurer<W> extends Configurer<Customization, W> {
+    void configure(Customization customization, W wrapper);
+}

+ 25 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/DocumentConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers;
+
+import com.ruoyi.project.office.documentserver.models.filemodel.Document;
+
+public interface DocumentConfigurer<W> extends Configurer<Document, W> {
+    void configure(Document document, W wrapper);
+}

+ 25 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/EditorConfigConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers;
+
+import com.ruoyi.project.office.documentserver.models.filemodel.EditorConfig;
+
+public interface EditorConfigConfigurer<W> extends Configurer<EditorConfig, W> {
+    void configure(EditorConfig editorConfig, W wrapper);
+}

+ 25 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/EmbeddedConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers;
+
+import com.ruoyi.project.office.documentserver.models.configurations.Embedded;
+
+public interface EmbeddedConfigurer<W> extends Configurer<Embedded, W> {
+    void configure(Embedded embedded, W wrapper);
+}

+ 26 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/FileConfigurer.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.ruoyi.project.office.services.configurers;
+
+import com.ruoyi.project.office.documentserver.models.filemodel.FileModel;
+
+public interface FileConfigurer<W> extends Configurer<FileModel, W> {
+    void configure(FileModel model, W wrapper);
+    FileModel getFileModel(W wrapper);
+}

+ 38 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultCustomizationConfigurer.java

@@ -0,0 +1,38 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.implementations;
+
+import com.ruoyi.project.office.documentserver.models.configurations.Customization;
+import com.ruoyi.project.office.documentserver.models.enums.Action;
+import com.ruoyi.project.office.entities.User;
+import com.ruoyi.project.office.services.configurers.CustomizationConfigurer;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultCustomizationWrapper;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+@Service
+@Primary
+public class DefaultCustomizationConfigurer implements CustomizationConfigurer<DefaultCustomizationWrapper> {
+    @Override
+    public void configure(Customization customization, DefaultCustomizationWrapper wrapper) {  // define the customization configurer
+        Action action = wrapper.getAction();  // get the action parameter from the customization wrapper
+        User user = wrapper.getUser();
+        customization.setSubmitForm(action.equals(Action.fillForms) && "1".equals(user.getId()) && false);  // set the submitForm parameter to the customization config
+    }
+}

+ 67 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultDocumentConfigurer.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.ruoyi.project.office.services.configurers.implementations;
+
+import com.ruoyi.project.office.documentserver.managers.document.DocumentManager;
+import com.ruoyi.project.office.documentserver.models.filemodel.Document;
+import com.ruoyi.project.office.documentserver.models.filemodel.Permission;
+import com.ruoyi.project.office.documentserver.storage.FileStoragePathBuilder;
+import com.ruoyi.project.office.documentserver.util.file.FileUtility;
+import com.ruoyi.project.office.documentserver.util.service.ServiceConverter;
+import com.ruoyi.project.office.entities.UserFile;
+import com.ruoyi.project.office.services.configurers.DocumentConfigurer;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultDocumentWrapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+@Service
+@Primary
+public class DefaultDocumentConfigurer implements DocumentConfigurer<DefaultDocumentWrapper> {
+
+    @Autowired
+    private DocumentManager documentManager;
+
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+
+    @Autowired
+    private FileUtility fileUtility;
+
+    @Autowired
+    private ServiceConverter serviceConverter;
+
+    public void configure(Document document, DefaultDocumentWrapper wrapper){  // define the document configurer
+        UserFile userFile = wrapper.getUserFile();
+
+        String fileName = userFile.getFileName() + "." + userFile.getExtendName();  // get the fileName parameter from the document wrapper
+        Permission permission = wrapper.getPermission();  // get the permission parameter from the document wrapper
+
+        document.setTitle(fileName);  // set the title to the document config
+        document.setUrl(wrapper.getPreviewUrl());  // set the URL to download a file to the document config
+        document.setFileType(fileUtility.getFileExtension(fileName).replace(".",""));  // set the file type to the document config
+        document.getInfo().setFavorite(wrapper.getFavorite());  // set the favorite parameter to the document config
+
+        String key =  serviceConverter.  // get the document key
+                        generateRevisionId(userFile.getUserFileId() + userFile.getUploadTime());
+
+        document.setKey(key);  // set the key to the document config
+        document.setPermissions(permission);  // set the permission parameters to the document config
+    }
+}

+ 105 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultEditorConfigConfigurer.java

@@ -0,0 +1,105 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.implementations;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.project.office.documentserver.managers.document.DocumentManager;
+import com.ruoyi.project.office.documentserver.managers.template.TemplateManager;
+import com.ruoyi.project.office.documentserver.models.enums.Action;
+import com.ruoyi.project.office.documentserver.models.enums.Mode;
+import com.ruoyi.project.office.documentserver.models.filemodel.EditorConfig;
+import com.ruoyi.project.office.documentserver.util.file.FileUtility;
+import com.ruoyi.project.office.entities.User;
+import com.ruoyi.project.office.entities.UserFile;
+import com.ruoyi.project.office.mappers.Mapper;
+import com.ruoyi.project.office.services.configurers.EditorConfigConfigurer;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultCustomizationWrapper;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultEmbeddedWrapper;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultFileWrapper;
+import lombok.SneakyThrows;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+
+@Service
+@Primary
+public class DefaultEditorConfigConfigurer implements EditorConfigConfigurer<DefaultFileWrapper> {
+
+    @Autowired
+    private Mapper<User, com.ruoyi.project.office.documentserver.models.filemodel.User> mapper;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Autowired
+    private DocumentManager documentManager;
+
+    @Autowired
+    @Qualifier("sample")
+    private TemplateManager templateManager;
+
+    @Autowired
+    private DefaultCustomizationConfigurer defaultCustomizationConfigurer;
+
+    @Autowired
+    private DefaultEmbeddedConfigurer defaultEmbeddedConfigurer;
+
+    @Autowired
+    private FileUtility fileUtility;
+
+    @SneakyThrows
+    public void configure(EditorConfig config, DefaultFileWrapper wrapper){  // define the editorConfig configurer
+//        if (wrapper.getActionData() != null) {  // check if the actionData is not empty in the editorConfig wrapper
+//            config.setActionLink(objectMapper.readValue(wrapper.getActionData(), (JavaType) new TypeToken<HashMap<String, Object>>() { }.getType()));  // set actionLink to the editorConfig
+//        }
+//        String fileName = wrapper.getFileName();  // set the fileName parameter from the editorConfig wrapper
+        UserFile userFile = wrapper.getUserFile();
+//        String fileExt = fileUtility.getFileExtension(fileName);
+        String fileName = userFile.getFileName() + "." + userFile.getExtendName();
+        boolean userIsAnon = wrapper.getUser().getName().equals("Anonymous");  // check if the user from the editorConfig wrapper is anonymous or not
+
+        config.setTemplates(userIsAnon ? null : templateManager.createTemplates(fileName));  // set a template to the editorConfig if the user is not anonymous
+        config.setCallbackUrl(documentManager.getCallback(userFile.getUserFileId()));  // set the callback URL to the editorConfig
+        config.setCreateUrl(userIsAnon ? null : documentManager.getCreateUrl(fileName, false));  // set the document URL where it will be created to the editorConfig if the user is not anonymous
+        config.setLang(wrapper.getLang());  // set the language to the editorConfig
+        Boolean canEdit = wrapper.getCanEdit();  // check if the file of the specified type can be edited or not
+        Action action = wrapper.getAction();  // get the action parameter from the editorConfig wrapper
+        config.setCoEditing(action.equals(Action.view) && userIsAnon ? new HashMap<String, Object>()  {{
+            put("mode", "strict");
+            put("change", false);
+        }} : new HashMap<String, Object>()  {{
+            put("mode", "fast");
+            put("change", true);
+        }});
+
+        defaultCustomizationConfigurer.configure(config.getCustomization(), DefaultCustomizationWrapper.builder()  // define the customization configurer
+                .action(action)
+                .user(userIsAnon ? null : wrapper.getUser())
+                .build());
+        config.setMode(canEdit && !action.equals(Action.view) ? Mode.edit : Mode.view);
+        config.setUser(mapper.toModel(wrapper.getUser()));
+        defaultEmbeddedConfigurer.configure(config.getEmbedded(), DefaultEmbeddedWrapper.builder()
+                .type(wrapper.getType())
+                .fileName(fileName)
+                .build());
+    }
+}

+ 47 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultEmbeddedConfigurer.java

@@ -0,0 +1,47 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.implementations;
+
+import com.ruoyi.project.office.documentserver.managers.document.DocumentManager;
+import com.ruoyi.project.office.documentserver.models.configurations.Embedded;
+import com.ruoyi.project.office.documentserver.models.enums.ToolbarDocked;
+import com.ruoyi.project.office.documentserver.models.enums.Type;
+import com.ruoyi.project.office.services.configurers.EmbeddedConfigurer;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultEmbeddedWrapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+@Service
+@Primary
+public class DefaultEmbeddedConfigurer implements EmbeddedConfigurer<DefaultEmbeddedWrapper> {
+
+    @Autowired
+    private DocumentManager documentManager;
+
+    public void configure(Embedded embedded, DefaultEmbeddedWrapper wrapper){  // define the embedded configurer
+        if(wrapper.getType().equals(Type.embedded)) {  // check if the type from the embedded wrapper is embedded
+            String url = documentManager.getDownloadUrl(wrapper.getFileName(), false);  // get file URL of the specified file
+            embedded.setEmbedUrl(url);  // set the embedURL parameter to the embedded config (the absolute URL to the document serving as a source file for the document embedded into the web page)
+            embedded.setSaveUrl(url);  // set the saveURL parameter to the embedded config (the absolute URL that will allow the document to be saved onto the user personal computer)
+            embedded.setShareUrl(url);  // set the shareURL parameter to the embedded config (the absolute URL that will allow other users to share this document)
+            embedded.setToolbarDocked(ToolbarDocked.top);  // set the top toolbarDocked parameter to the embedded config (the place for the embedded viewer toolbar, can be either top or bottom)
+        };
+    }
+}

+ 138 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/implementations/DefaultFileConfigurer.java

@@ -0,0 +1,138 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.implementations;
+
+import com.ruoyi.project.office.documentserver.managers.jwt.JwtManager;
+import com.ruoyi.project.office.documentserver.models.enums.Action;
+import com.ruoyi.project.office.documentserver.models.enums.DocumentType;
+import com.ruoyi.project.office.documentserver.models.filemodel.FileModel;
+import com.ruoyi.project.office.documentserver.models.filemodel.Permission;
+import com.ruoyi.project.office.documentserver.util.file.FileUtility;
+import com.ruoyi.project.office.entities.UserFile;
+import com.ruoyi.project.office.mappers.Mapper;
+import com.ruoyi.project.office.services.configurers.FileConfigurer;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultDocumentWrapper;
+import com.ruoyi.project.office.services.configurers.wrappers.DefaultFileWrapper;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+public class DefaultFileConfigurer implements FileConfigurer<DefaultFileWrapper> {
+    @Autowired
+    private ObjectFactory<FileModel> fileModelObjectFactory;
+
+    @Autowired
+    private FileUtility fileUtility;
+
+    @Autowired
+    private JwtManager jwtManager;
+
+    @Autowired
+    private Mapper<com.ruoyi.project.office.entities.Permission, Permission> mapper;
+
+    @Autowired
+    private DefaultDocumentConfigurer defaultDocumentConfigurer;
+
+    @Autowired
+    private DefaultEditorConfigConfigurer defaultEditorConfigConfigurer;
+
+    public void configure(FileModel fileModel, DefaultFileWrapper wrapper){  // define the file configurer
+        if (fileModel != null){  // check if the file model is specified
+            UserFile userFile = wrapper.getUserFile();  // get the fileName parameter from the file wrapper
+            Action action = wrapper.getAction();  // get the action parameter from the file wrapper
+
+//            DocumentType documentType = fileUtility.getDocumentType(userFile.getFileName() + "." + userFile.getExtendName());  // get the document type of the specified file
+            DocumentType documentType = fileUtility.getDocumentType(userFile.getFileName());
+            fileModel.setDocumentType(documentType);  // set the document type to the file model
+            fileModel.setType(wrapper.getType());  // set the platform type to the file model
+
+//            Permission userPermissions = mapper.toModel(wrapper.getUser().getPermissions());  // convert the permission entity to the model
+            Permission userPermissions = new Permission(); // TODO
+
+            String fileExt = fileUtility.getFileExtension(userFile.getFileName());
+            Boolean canEdit = fileUtility.getEditedExts().contains(fileExt);
+            if ((!canEdit && action.equals(Action.edit) || action.equals(Action.fillForms)) && fileUtility.getFillExts().contains(fileExt)) {
+                canEdit = true;
+                wrapper.setAction(Action.fillForms);
+            }
+            wrapper.setCanEdit(canEdit);
+
+            DefaultDocumentWrapper documentWrapper = DefaultDocumentWrapper  // define the document wrapper
+                    .builder()
+                    .userFile(userFile)
+//                    .fileName(userFile.getFileName() + "." + userFile.getExtendName())
+                    .permission(updatePermissions(userPermissions, action, canEdit))
+                    .favorite(wrapper.getUser().getFavorite())
+                    .previewUrl(wrapper.getActionData())
+                    .build();
+
+            defaultDocumentConfigurer.configure(fileModel.getDocument(),  documentWrapper);  // define the document configurer
+            defaultEditorConfigConfigurer.configure(fileModel.getEditorConfig(), wrapper);  // define the editorConfig configurer
+
+            Map<String, Object> map = new HashMap<>();
+            map.put("type", fileModel.getType());
+            map.put("documentType", documentType);
+            map.put("document", fileModel.getDocument());
+            map.put("editorConfig", fileModel.getEditorConfig());
+
+            fileModel.setToken(jwtManager.createToken(map));  // create a token and set it to the file model
+
+        }
+    }
+
+
+
+    @Override
+    public FileModel getFileModel(DefaultFileWrapper wrapper) {  // get file model
+        FileModel fileModel = fileModelObjectFactory.getObject();
+        configure(fileModel, wrapper);  // and configure it
+        return fileModel;
+    }
+
+    private Permission updatePermissions(Permission userPermissions, Action action, Boolean canEdit) {
+        userPermissions.setComment(
+                !action.equals(Action.view)
+                        && !action.equals(Action.fillForms)
+                        && !action.equals(Action.embedded)
+                        && !action.equals(Action.blockcontent)
+        );
+
+        userPermissions.setFillForms(
+                !action.equals(Action.view)
+                        && !action.equals(Action.comment)
+                        && !action.equals(Action.embedded)
+                        && !action.equals(Action.blockcontent)
+        );
+
+        userPermissions.setReview(canEdit &&
+                (action.equals(Action.review) || action.equals(Action.edit)));
+
+        userPermissions.setEdit(canEdit &&
+                (action.equals(Action.view)
+                || action.equals(Action.edit)
+                || action.equals(Action.filter)
+                || action.equals(Action.blockcontent)));
+
+        return userPermissions;
+    }
+}

+ 31 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultCustomizationWrapper.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.wrappers;
+
+import com.ruoyi.project.office.documentserver.models.enums.Action;
+import com.ruoyi.project.office.entities.User;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class DefaultCustomizationWrapper {
+    private Action action;
+    private User user;
+}

+ 33 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultDocumentWrapper.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.wrappers;
+
+import com.ruoyi.project.office.documentserver.models.filemodel.Permission;
+import com.ruoyi.project.office.entities.UserFile;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class DefaultDocumentWrapper {
+    private Permission permission;
+    private UserFile userFile;
+    private Boolean favorite;
+    private String previewUrl;
+}

+ 30 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultEmbeddedWrapper.java

@@ -0,0 +1,30 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.wrappers;
+
+import com.ruoyi.project.office.documentserver.models.enums.Type;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class DefaultEmbeddedWrapper {
+    private Type type;
+    private String fileName;
+}

+ 40 - 0
admin/src/main/java/com/ruoyi/project/office/services/configurers/wrappers/DefaultFileWrapper.java

@@ -0,0 +1,40 @@
+/**
+ *
+ * (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.ruoyi.project.office.services.configurers.wrappers;
+
+import com.ruoyi.project.office.documentserver.models.enums.Action;
+import com.ruoyi.project.office.documentserver.models.enums.Type;
+import com.ruoyi.project.office.entities.User;
+import com.ruoyi.project.office.entities.UserFile;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Builder
+@Setter
+public class DefaultFileWrapper {
+    private UserFile userFile;
+    private Type type;
+    private User user;
+    private String lang;
+    private Action action;
+    private String actionData;
+    private Boolean canEdit;
+}

+ 2 - 2
admin/src/main/resources/application-druid.yml

@@ -6,9 +6,9 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                url: jdbc:mysql://43.143.92.79:3306/newcpms_sh?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                 username: root
-                password: password
+                password: Ssy666666!
             # 从库数据源
             slave:
                 # 从数据源开关/默认关闭

+ 37 - 4
admin/src/main/resources/application.yml

@@ -7,7 +7,7 @@ ruoyi:
   # 版权年份
   copyrightYear: 2024
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
-  profile: D:/ruoyi/uploadPath
+  profile: D:/cpmsFile/uploadPath
   # 获取ip地址开关
   addressEnabled: false
   # 验证码类型 math 数字计算 char 字符验证
@@ -68,13 +68,13 @@ spring:
   # redis 配置
   redis:
     # 地址
-    host: localhost
+    host: 47.114.101.16
     # 端口,默认为6379
     port: 6379
     # 数据库索引
-    database: 0
+    database: 2
     # 密码
-    password:
+    password: ssy666666
     # 连接超时时间
     timeout: 10s
     lettuce:
@@ -127,3 +127,36 @@ xss:
   excludes: /system/notice
   # 匹配链接
   urlPatterns: /system/*,/monitor/*,/tool/*
+jasypt:
+  encryptor:
+    password: test
+# 当前部署外网IP,用于office预览
+deployment:
+  host: cpms.free.idcfengye.com/dev-api
+filesize-max: 5242880
+files:
+  docservice:
+    convert-docs: .docm|.dotx|.dotm|.dot|.doc|.odt|.fodt|.ott|.xlsm|.xlsb|.xltx|.xltm|.xlt|.xls|.ods|.fods|.ots|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.rtf|.mht|.html|.htm|.xml|.epub|.fb2
+    edited-docs: .docx|.xlsx|.csv|.pptx|.txt|.docxf
+    fillforms-docs: .oform|.docx
+    header: Authorization
+    history:
+      postfix: -hist
+    languages: en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (People's Republic of China)|zh-TW:Chinese (Traditional, Taiwan)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lv:Latvian|lo:Lao|ms:Malay (Malaysia)|nb:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese
+    secret: secret
+    timeout: 120000
+    url:
+      api: web-apps/apps/api/documents/api.js
+      command: coauthoring/CommandService.ashx
+      converter: ConvertService.ashx
+      example: ''
+      preloader: web-apps/apps/api/documents/cache-scripts.html
+      site: http://39.98.183.28:6831/
+    verify-peer-off: true
+    viewed-docs: .pdf|.djvu|.xps|.oxps
+  storage: ''
+  storage.folder: documents
+logo:
+  image: ''
+  imageEmbedded: ''
+  url: https://www.onlyoffice.com

+ 1 - 1
framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java

@@ -64,7 +64,7 @@ public class SysLoginService
     public String login(String username, String password, String code, String uuid)
     {
         // 验证码校验
-        validateCaptcha(username, code, uuid);
+//        validateCaptcha(username, code, uuid);
         // 登录前置校验
         loginPreCheck(username, password);
         // 用户验证

+ 1 - 1
ui/package.json

@@ -2,7 +2,7 @@
   "name": "ruoyi",
   "version": "3.8.7",
   "description": "CPMS管理系统",
-  "author": "若依",
+  "author": "admin",
   "license": "MIT",
   "scripts": {
     "dev": "vue-cli-service serve",

+ 19 - 0
ui/src/api/onlyoffice/onlyoffice.js

@@ -0,0 +1,19 @@
+import request from '@/utils/request'
+
+// 编辑
+export function editOfficeFile(data) {
+  return request({
+    url: '/onlyoffice/editFile',
+    method: 'post',
+    data: data
+  })
+}
+// 查看
+export function previewFile(data) {
+  return request({
+    url: '/onlyoffice/previewFile',
+    method: 'post',
+    data: data
+  })
+}
+

BIN
ui/src/assets/images/profile.jpg


+ 27 - 14
ui/src/router/index.js

@@ -20,12 +20,12 @@ import Layout from '@/layout'
  * roles: ['admin', 'common']       // 访问路由的角色权限
  * permissions: ['a:a:a', 'b:b:b']  // 访问路由的菜单权限
  * meta : {
-    noCache: true                   // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
-    title: 'title'                  // 设置该路由在侧边栏和面包屑中展示的名字
-    icon: 'svg-name'                // 设置该路由的图标,对应路径src/assets/icons/svg
-    breadcrumb: false               // 如果设置为false,则不会在breadcrumb面包屑中显示
-    activeMenu: '/system/user'      // 当路由设置了该属性,则会高亮相对应的侧边栏。
-  }
+ noCache: true                   // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
+ title: 'title'                  // 设置该路由在侧边栏和面包屑中展示的名字
+ icon: 'svg-name'                // 设置该路由的图标,对应路径src/assets/icons/svg
+ breadcrumb: false               // 如果设置为false,则不会在breadcrumb面包屑中显示
+ activeMenu: '/system/user'      // 当路由设置了该属性,则会高亮相对应的侧边栏。
+ }
  */
 
 // 公共路由
@@ -70,7 +70,7 @@ export const constantRoutes = [
         path: 'index',
         component: () => import('@/views/index'),
         name: 'Index',
-        meta: { title: '首页', icon: 'dashboard', affix: true }
+        meta: {title: '首页', icon: 'dashboard', affix: true}
       }
     ]
   },
@@ -84,7 +84,7 @@ export const constantRoutes = [
         path: 'profile',
         component: () => import('@/views/system/user/profile/index'),
         name: 'Profile',
-        meta: { title: '个人中心', icon: 'user' }
+        meta: {title: '个人中心', icon: 'user'}
       }
     ]
   }
@@ -102,7 +102,7 @@ export const dynamicRoutes = [
         path: 'role/:userId(\\d+)',
         component: () => import('@/views/system/user/authRole'),
         name: 'AuthRole',
-        meta: { title: '分配角色', activeMenu: '/system/user' }
+        meta: {title: '分配角色', activeMenu: '/system/user'}
       }
     ]
   },
@@ -116,7 +116,7 @@ export const dynamicRoutes = [
         path: 'user/:roleId(\\d+)',
         component: () => import('@/views/system/role/authUser'),
         name: 'AuthUser',
-        meta: { title: '分配用户', activeMenu: '/system/role' }
+        meta: {title: '分配用户', activeMenu: '/system/role'}
       }
     ]
   },
@@ -130,7 +130,7 @@ export const dynamicRoutes = [
         path: 'index/:dictId(\\d+)',
         component: () => import('@/views/system/dict/data'),
         name: 'Data',
-        meta: { title: '字典数据', activeMenu: '/system/dict' }
+        meta: {title: '字典数据', activeMenu: '/system/dict'}
       }
     ]
   },
@@ -144,7 +144,7 @@ export const dynamicRoutes = [
         path: 'index/:jobId(\\d+)',
         component: () => import('@/views/monitor/job/log'),
         name: 'JobLog',
-        meta: { title: '调度日志', activeMenu: '/monitor/job' }
+        meta: {title: '调度日志', activeMenu: '/monitor/job'}
       }
     ]
   },
@@ -158,9 +158,22 @@ export const dynamicRoutes = [
         path: 'index/:tableId(\\d+)',
         component: () => import('@/views/tool/gen/editTable'),
         name: 'GenEdit',
-        meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
+        meta: {title: '修改生成配置', activeMenu: '/tool/gen'}
       }
     ]
+  },
+  {
+    path: '/ehs',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'edit',
+        component: (resolve) => require(['@/views/onlyoffice/edit'], resolve),
+        name: 'file',
+        meta: {title: '在线编辑'}
+      }
+    ],
   }
 ]
 
@@ -178,6 +191,6 @@ Router.prototype.replace = function push(location) {
 
 export default new Router({
   mode: 'history', // 去掉url中的#
-  scrollBehavior: () => ({ y: 0 }),
+  scrollBehavior: () => ({y: 0}),
   routes: constantRoutes
 })

+ 3 - 26
ui/src/views/login.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="login">
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
-      <h3 class="title">若依后台管理系统</h3>
+      <h3 class="title">CPMS管理系统</h3>
       <el-form-item prop="username">
         <el-input
           v-model="loginForm.username"
@@ -23,20 +23,7 @@
           <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
         </el-input>
       </el-form-item>
-      <el-form-item prop="code" v-if="captchaEnabled">
-        <el-input
-          v-model="loginForm.code"
-          auto-complete="off"
-          placeholder="验证码"
-          style="width: 63%"
-          @keyup.enter.native="handleLogin"
-        >
-          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
-        </el-input>
-        <div class="login-code">
-          <img :src="codeUrl" @click="getCode" class="login-code-img"/>
-        </div>
-      </el-form-item>
+
       <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
       <el-form-item style="width:100%;">
         <el-button
@@ -56,13 +43,12 @@
     </el-form>
     <!--  底部  -->
     <div class="el-login-footer">
-      <span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
+      <span>Copyright © 2018-2024 Seashore All Rights Reserved.</span>
     </div>
   </div>
 </template>
 
 <script>
-import { getCodeImg } from "@/api/login";
 import Cookies from "js-cookie";
 import { encrypt, decrypt } from '@/utils/jsencrypt'
 
@@ -108,15 +94,6 @@ export default {
     this.getCookie();
   },
   methods: {
-    getCode() {
-      getCodeImg().then(res => {
-        this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
-        if (this.captchaEnabled) {
-          this.codeUrl = "data:image/gif;base64," + res.img;
-          this.loginForm.uuid = res.uuid;
-        }
-      });
-    },
     getCookie() {
       const username = Cookies.get("username");
       const password = Cookies.get("password");

+ 198 - 0
ui/src/views/onlyoffice/edit.vue

@@ -0,0 +1,198 @@
+<template>
+  <div class="report-onlyoffice">
+    <div id="placeholder"></div>
+  </div>
+</template>
+
+<script>
+import {editOfficeFile, previewFile} from "@/api/onlyoffice/onlyoffice";
+
+export default {
+  name: 'OnlyOffice',
+  data() {
+    return {
+      docEditor: null, //  文档编辑器
+      platform: 'desktop', //  查看平台
+    }
+  },
+  computed: {
+    // 文件信息,来自于路由参数query
+    fileInfo() {
+      return this.$route.query
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      switch (this.fileInfo.ot) {
+        // 添加
+        // case 'add':
+        //   this.initOnlyoffice()
+        //   break
+        // 编辑
+        case 'edit':
+          this.editDoc()
+          break
+        // 详情
+        case 'detail':
+          this.showDocDetail()
+          break
+      }
+    })
+
+    // the application is loaded into the browser
+    let onAppReady = function () {
+      // Your code here
+    };
+
+    // the document is modified
+    let onDocumentStateChange = function (event) {
+      // Your code here
+    };
+
+    // the user is trying to switch the document from the viewing into the editing mode
+    let onRequestEditRights = function () {
+      // Your code here
+    };
+
+    // an error or some other specific event occurs
+    let onError = function (event) {
+      // Your code here
+    };
+
+    // the document is opened for editing with the old document.key value
+    let onOutdatedVersion = function (event) {
+      // Your code here
+    };
+
+    // replace the link to the document which contains a bookmark
+    let replaceActionLink = function (href, linkParam) {
+      // Your code here
+    };
+
+    // the user is trying to get link for opening the document which contains a bookmark, scrolling to the bookmark position
+    let onMakeActionLink = function (event) {
+      // Your code here
+    };
+
+    // the meta information of the document is changed via the meta command
+    let onMetaChange = function (event) {
+      // Your code here
+    };
+
+    let onRequestInsertImage = function (event) {
+      // Your code here
+    };
+
+    let onRequestCompareFile = function () {
+      // Your code here
+    };
+
+    let onRequestMailMergeRecipients = function (event) {
+      // Your code here
+    };
+
+    // config.events = {
+    //   "onAppReady": onAppReady,
+    //   "onDocumentStateChange": onDocumentStateChange,
+    //   'onRequestEditRights': onRequestEditRights,
+    //   "onError": onError,
+    //   "onOutdatedVersion": onOutdatedVersion,
+    //   "onMakeActionLink": onMakeActionLink,
+    //   "onMetaChange": onMetaChange,
+    //   "onRequestInsertImage": onRequestInsertImage,
+    //   "onRequestCompareFile": onRequestCompareFile,
+    //   "onRequestMailMergeRecipients": onRequestMailMergeRecipients,
+    // };
+
+  },
+  methods: {
+    /**
+     * 编辑文档
+     */
+    editDoc() {
+      let data = {
+        userFileId: this.fileInfo.fileId,
+        previewUrl: this.fileInfo.fileUrl
+      }
+      editOfficeFile(data).then((res) => {
+        if (res.code === 200) {
+          // let config = {
+          // 	...res.data.file,
+          // 	type: this.platform
+          // }
+          this.initDocEditor(res.data.docserviceApiUrl, res.data.file)
+        }
+      })
+    },
+    /**
+     * 查看文档
+     */
+    showDocDetail() {
+      let data = {
+        userFileId: this.fileInfo.fileId,
+        previewUrl: this.fileInfo.fileUrl
+      }
+      previewFile(data).then((res) => {
+        if (res.code === 200) {
+          // let config = {
+          // 	...res.data.file,
+          // 	type: this.platform
+          // }
+          this.initDocEditor(res.data.docserviceApiUrl, res.data.file)
+        }
+      })
+    },
+    /**
+     * 初始化文档编辑器
+     * @param {string} docserviceApiUrl 文档服务API url
+     * @param {object} config 文件相关配置信息
+     */
+    initDocEditor(docserviceApiUrl, config) {
+
+      this.loadOnlyOfficeAPI(docserviceApiUrl).then(() => {
+        console.log(config)
+        /* global DocsAPI */
+        // this.docEditor = new DocsAPI.DocEditor('placeholder', this.myConfig)
+
+        this.docEditor = new DocsAPI.DocEditor('placeholder', {
+          ...config,
+          editorConfig: {
+            ...config.editorConfig,
+            lang: 'zh', //  语言设置为中文
+            customization: {
+              ...config.editorConfig.customization,
+              zoom: 100 //  缩放比例为 100
+            }
+          }
+        })
+
+      })
+    },
+    /**
+     * 加载 onlyoffice api
+     * @return {Promise} 返回 api 加载状态
+     */
+    loadOnlyOfficeAPI(src) {
+      return new Promise((resolve, reject) => {
+        const script = document.createElement('script')
+        script.type = 'text/javascript'
+        script.src = src
+        document.body.appendChild(script)
+        script.onload = () => {
+          resolve()
+        }
+        script.onerror = () => {
+          reject()
+        }
+      })
+    }
+  }
+};
+</script>
+
+<style scoped>
+.report-onlyoffice {
+  height: 700px;
+  width: 100%;
+}
+</style>

+ 771 - 0
ui/src/views/onlyoffice/index.vue

@@ -0,0 +1,771 @@
+<template>
+  <div class="app-container">
+    <el-form v-show="showSearch" ref="queryForm" :inline="true" :model="queryParams" label-width="68px" size="small">
+
+      <el-form-item>
+        <el-button icon="el-icon-search" size="mini" type="primary" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+            v-hasPermi="['ehs:approval:add']"
+            icon="el-icon-plus"
+            plain
+            size="mini"
+            type="primary"
+            @click="handleAdd"
+        >新增
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            v-hasPermi="['ehs:approval:edit']"
+            :disabled="single"
+            icon="el-icon-edit"
+            plain
+            size="mini"
+            type="success"
+            @click="handleUpdate"
+        >修改
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            v-hasPermi="['ehs:approval:remove']"
+            :disabled="multiple"
+            icon="el-icon-delete"
+            plain
+            size="mini"
+            type="danger"
+            @click="handleDelete"
+        >删除
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            v-hasPermi="['ehs:approval:export']"
+            icon="el-icon-download"
+            plain
+            size="mini"
+            type="warning"
+            @click="handleExport"
+        >导出
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            v-hasPermi="['sems:specDt:edit']"
+            icon="el-icon-upload2"
+            size="mini"
+            type="info"
+            @click="handleImport"
+        >{{ $t('导入') }}
+        </el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="approvalList" :height="clientHeight" border
+              @selection-change="handleSelectionChange">
+      <el-table-column align="center" type="selection" width="55"/>
+      <el-table-column align="center" label="批文属性" prop="approvalAttibutes" width="100"/>
+      <el-table-column align="center" label="批准日期" prop="effetivedate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.effetivedate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="项目名称" prop="itemName" width="150"/>
+      <el-table-column align="center" label="项目概况" prop="itemOverview" width="150"/>
+      <el-table-column align="center" label="批文名称" prop="approvalname" width="150"/>
+      <el-table-column align="center" label="批文编号" prop="fileno" width="150"/>
+      <el-table-column align="center" label="审批单位" prop="responsauth" width="150"/>
+      <el-table-column align="center" label="主要内容" prop="content" width="200">
+        <template slot-scope="scope">
+          <span v-if="scope.row.content" style="white-space: pre-line">{{ scope.row.content + '\n' }}</span>
+          <span v-if="scope.row.contentFile">
+            <el-image
+                v-for="item in scope.row.contentFile"
+                :preview-src-list="scope.row.contentFile"
+                :src="item"
+                style="width: 100px; height: 100px;">
+            </el-image>
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="适用范围" prop="scope" width="200"/>
+      <el-table-column align="center" label="相关法规" prop="relatedlaw" width="200"/>
+      <el-table-column align="center" label="证书有效期" width="180">
+        <template slot-scope="scope">
+          <span v-if="scope.row.isPermanent==1">永久</span>
+          <span v-if="scope.row.isPermanent==0">
+            {{ parseTime(scope.row.validityBefore, '{y}-{m}-{d}') }} ~
+            {{ parseTime(scope.row.validityAfter, '{y}-{m}-{d}') }}
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="是否需要跟进" prop="follow" width="120"/>
+      <el-table-column align="center" label="负责人" prop="owner" width="120"/>
+      <el-table-column align="center" label="回顾人" prop="reviewer" width="120"/>
+      <el-table-column align="center" label="回顾时间" prop="reviewdate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.reviewdate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="是否合规" prop="isCompliance" width="120"/>
+      <el-table-column align="center" label="下次回顾时间" prop="nextreviewdate" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.nextreviewdate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="备注" prop="remarks" width="120"/>
+      <el-table-column align="center" class-name="small-padding fixed-width" fixed="right" label="操作" width="120">
+        <template slot-scope="scope">
+          <el-button
+              icon="el-icon-folder"
+              size="mini"
+              type="text"
+              @click="openFileDialog(scope.row)"
+          >附件
+          </el-button>
+          <el-button
+              v-hasPermi="['ehs:approval:edit']"
+              icon="el-icon-edit"
+              size="mini"
+              type="text"
+              @click="handleUpdate(scope.row)"
+          >修改
+          </el-button>
+          <el-button
+              v-hasPermi="['ehs:approval:remove']"
+              icon="el-icon-delete"
+              size="mini"
+              type="text"
+              @click="handleDelete(scope.row)"
+          >删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+        v-show="total>0"
+        :limit.sync="queryParams.pageSize"
+        :page.sync="queryParams.pageNum"
+        :total="total"
+        @pagination="getList"
+    />
+
+    <!-- 添加或修改批文清单对话框 -->
+    <el-dialog :close-on-click-modal="false" :title="title" :visible.sync="open" append-to-body width="40%">
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-form-item label="批准日期" prop="effetivedate">
+          <el-date-picker v-model="form.effetivedate"
+                          clearable
+                          placeholder="请选择批准日期"
+                          type="date"
+                          value-format="yyyy-MM-dd">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="项目名称" prop="itemName">
+          <el-input v-model="form.itemName" placeholder="请输入项目名称"/>
+        </el-form-item>
+        <el-form-item label="项目概况" prop="itemOverview">
+          <el-input v-model="form.itemOverview" placeholder="请输入内容" type="textarea"/>
+        </el-form-item>
+        <el-form-item label="批文属性" prop="approvalAttibutes">
+          <el-input v-model="form.approvalAttibutes" placeholder="请输入批文属性"/>
+        </el-form-item>
+        <el-form-item label="批文名称" prop="approvalname">
+          <el-input v-model="form.approvalname" placeholder="请输入内容" type="textarea"/>
+        </el-form-item>
+        <el-form-item label="批文编号" prop="fileno">
+          <el-input v-model="form.fileno" placeholder="请输入批文编号"/>
+        </el-form-item>
+        <el-form-item label="审批单位" prop="responsauth">
+          <el-input v-model="form.responsauth" placeholder="请输入内容" type="textarea"/>
+        </el-form-item>
+        <el-form-item label="主要内容" prop="content">
+          <span>包含图文?</span>
+          <el-checkbox v-model="form.isInclude"/>
+          <el-input v-model="form.content" placeholder="请输入内容" type="textarea"/>
+          <el-upload
+              v-if="form.isInclude"
+              ref="picture"
+              :action="picture.url"
+              :file-list="fileList"
+              :headers="picture.headers"
+              :on-remove="handleRemovePic"
+              :on-success="handlePicSuccess"
+              list-type="picture-card" style="display: inline-block;margin-top: 5px">
+            <i class="el-icon-plus "></i>
+          </el-upload>
+        </el-form-item>
+        <el-form-item label="适用范围" prop="scope">
+          <el-input v-model="form.scope" placeholder="请输入内容" type="textarea"/>
+        </el-form-item>
+        <el-form-item label="相关法规" prop="relatedlaw">
+          <el-input v-model="form.relatedlaw" placeholder="请输入内容" type="textarea"/>
+        </el-form-item>
+        <el-form-item label="有效期是否永久" prop="isPermanent">
+          <el-radio v-model="form.isPermanent" label="0">否</el-radio>
+          <el-radio v-model="form.isPermanent" label="1">是</el-radio>
+        </el-form-item>
+        <el-form-item v-if="form.isPermanent==0" label="证书有效期" prop="validityBefore">
+          <el-date-picker v-model="form.validityBefore"
+                          clearable
+                          placeholder="请选择证书生效日期"
+                          type="date"
+                          value-format="yyyy-MM-dd">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item v-if="form.isPermanent==0" label="证书有效期" prop="validityAfter">
+          <el-date-picker v-model="form.validityAfter"
+                          clearable
+                          placeholder="请选择证书截止日期"
+                          type="date"
+                          value-format="yyyy-MM-dd">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="是否需要跟进" prop="follow">
+          <el-input v-model="form.follow" placeholder="请输入是否需要跟进"/>
+        </el-form-item>
+        <el-form-item label="负责人" prop="owner">
+          <el-input v-model="form.owner" placeholder="请输入负责人"/>
+        </el-form-item>
+        <el-form-item label="回顾人" prop="reviewer">
+          <el-input v-model="form.reviewer" placeholder="请输入回顾人"/>
+        </el-form-item>
+        <el-form-item label="回顾时间" prop="reviewdate">
+          <el-date-picker v-model="form.reviewdate"
+                          clearable
+                          placeholder="请选择回顾时间"
+                          type="date"
+                          value-format="yyyy-MM-dd">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="是否合规" prop="isCompliance">
+          <el-input v-model="form.isCompliance" placeholder="请输入是否合规"/>
+        </el-form-item>
+        <el-form-item label="下次回顾时间" prop="nextreviewdate">
+          <el-date-picker v-model="form.nextreviewdate"
+                          clearable
+                          placeholder="请选择下次回顾时间"
+                          type="date"
+                          value-format="yyyy-MM-dd">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="备注" prop="remarks">
+          <el-input v-model="form.remarks" placeholder="请输入内容" type="textarea"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog :close-on-click-modal="false" :visible.sync="file.open" append-to-body title="附件管理" width="60%">
+      <el-row :gutter="10" class="mb8">
+        <el-col :span="1.5">
+          <el-button
+              icon="el-icon-plus"
+              plain
+              size="mini"
+              type="primary"
+              @click="handleFileAdd"
+          >新增
+          </el-button>
+        </el-col>
+      </el-row>
+      <el-table  :data="file.fileList" :height="clientHeight-100"
+                border>
+        <el-table-column align="center" label="附件名称" prop="fileName">
+            <template slot-scope="scope">
+              <el-button
+                  size="mini"
+                  type="text"
+                  @click="previewFile(scope.row.fileUrl)"
+              >{{ scope.row.fileName }}
+              </el-button>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="上传时间" prop="uploadDate" width="180">
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.uploadDate, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column align="center" label="上传人" prop="uploader">
+        </el-table-column>
+        <el-table-column align="center" class-name="small-padding fixed-width" label="操作">
+          <template slot-scope="scope">
+            <el-button
+              icon="el-icon-delete"
+              size="mini"
+              type="text"
+              @click="handleFileView(scope.row)"
+            >查看
+            </el-button>
+            <el-button
+                icon="el-icon-delete"
+                size="mini"
+                type="text"
+                @click="handleFileRemove(scope.row)"
+            >删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination
+          v-show="file.total>0"
+          :limit.sync="file.queryParams.pageSize"
+          :page.sync="file.queryParams.pageNum"
+          :total="file.total"
+          @pagination="getFileList"
+      />
+    </el-dialog>
+    <el-dialog :close-on-click-modal="false" :visible.sync="doc.open" append-to-body title="附件上传" width="400px">
+      <el-upload
+          ref="doc"
+          :action="doc.url"
+          :auto-upload="false"
+          :file-list="doc.fileList"
+          :headers="doc.headers"
+          :on-progress="handleFileDocProgress"
+          :on-success="handleFileDocSuccess"
+          drag
+          multiple>
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+      </el-upload>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitUpload">确 定</el-button>
+        <el-button @click="cancelUpload">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 用户导入对话框 -->
+    <el-dialog :close-on-click-modal="false" v-dialogDrag :title="upload.title" :visible.sync="upload.open" append-to-body width="400px">
+      <el-upload
+          ref="upload"
+          :action="upload.url + '?updateSupport=' + upload.updateSupport"
+          :auto-upload="false"
+          :disabled="upload.isUploading"
+          :headers="upload.headers"
+          :limit="1"
+          :on-progress="handleFileUploadProgress"
+          :on-success="handleFileSuccess"
+          accept=".xlsx, .xls"
+          drag
+      >
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">
+          {{ $t('将文件拖到此处,或') }}
+          <em>{{ $t('点击上传') }}</em>
+        </div>
+        <div slot="tip" class="el-upload__tip">
+          <!--                  <el-checkbox v-model="upload.updateSupport" />{{ $t('是否更新已经存在的用户数据') }}-->
+          <el-link style="font-size:12px" type="info" @click="importTemplate">{{ $t('下载模板') }}</el-link>
+        </div>
+        <form ref="downloadFileForm" :action="upload.downloadAction" target="FORMSUBMIT">
+          <input :value="upload.type" hidden name="type"/>
+        </form>
+        <div slot="tip" class="el-upload__tip" style="color:red">{{ $t('提示:仅允许导入“xls”或“xlsx”格式文件!') }}</div>
+      </el-upload>
+      <div slot="footer" class="dialog-footer">
+        <a v-if="waitSubmit" style="margin-right: 300px">{{ $t('正在导入...') }}</a>
+        <el-button v-loading.fullscreen.lock="fullscreenLoading" type="primary"
+                   @click="submitFileForm">{{ $t('确 定') }}
+        </el-button>
+        <el-button @click="upload.open = false">{{ $t('取 消') }}</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {addApproval, delApproval, getApproval, listApproval, updateApproval} from "@/api/ehs/approval";
+import {getToken} from "../../../utils/auth";
+import {exportApproval} from "../../../api/ehs/approval";
+import {delFile, listFile} from "../../../api/file/file";
+
+export default {
+  name: "Approval",
+  data() {
+    return {
+      fullscreenLoading: false,
+      waitSubmit: false,
+      file: {
+        open: false,
+        fileList: [],
+        queryParams: {
+          pageNum: 1,
+          pageSize: 10,
+          linkId: null,
+          linkName: 'ehsApproval',
+        },
+        total:0,
+      },
+      doc: {
+        id: null,
+        file: "",
+        fileList: [],
+        // 是否显示弹出层
+        open: false,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/file/file/uploadFile",
+      },
+      upload: {
+        downloadAction: process.env.VUE_APP_BASE_API + '/common/template',
+        // 是否显示弹出层(用户导入)
+        type: "approval",
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: "",
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/ehs/approval/importData"
+      },
+      picUrl: [],
+      fileList: [],
+      picture: {
+        file: "",
+        // 报告附件上传位置编号
+        ids: 0,
+        // 设置上传的请求头部
+        headers: {Authorization: "Bearer " + getToken()},
+        // 上传的地址
+        url: process.env.VUE_APP_BASE_API + "/ehs/environapproval/uploadPic",
+      },
+      // 页面高度
+      clientHeight: 300,
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: false,
+      // 总条数
+      total: 0,
+      // 批文清单表格数据
+      approvalList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        plantCode: null,
+        division: null,
+        effetivedate: null,
+        itemName: null,
+        itemOverview: null,
+        approvalAttibutes: null,
+        approvalname: null,
+        fileno: null,
+        responsauth: null,
+        content: null,
+        scope: null,
+        relatedlaw: null,
+        validityBefore: null,
+        validityAfter: null,
+        isPermanent: null,
+        follow: null,
+        owner: null,
+        reviewer: null,
+        reviewdate: null,
+        isCompliance: null,
+        nextreviewdate: null,
+        remarks: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        deptId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        approvalname: [
+          {required: true, message: "批文名称不能为空", trigger: "blur"}
+        ],
+        fileno: [
+          {required: true, message: "批文编号不能为空", trigger: "blur"}
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+    //设置表格高度对应屏幕高度
+    this.$nextTick(() => {
+      this.clientHeight = (document.body.clientHeight - 80) * 0.8
+    });
+  },
+  methods: {
+    // 文件上传中处理
+    handleFileUploadProgress(event, file, fileList) {
+      this.waitSubmit = true;
+      this.upload.isUploading = true;
+    },
+    // 文件上传成功处理
+    handleFileSuccess(response, file, fileList) {
+      this.waitSubmit = false;
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.$refs.upload.clearFiles();
+      this.fullscreenLoading = false;
+      if (response.data.length > 0) {
+        let failrow = ''
+        for (let i = 0; i < response.data.length; i++) {
+          failrow += response.data[i] + ','
+        }
+        this.$alert(this.$t('导入成功条数:') + response.msg + '<br>' + this.$t('失败行数:') + failrow, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      } else {
+        this.$alert(this.$t('导入成功条数:') + response.msg, this.$t('导入结果'), {dangerouslyUseHTMLString: true});
+      }
+      this.getList();
+    },
+    // 提交上传文件
+    submitFileForm() {
+      this.$refs.upload.submit();
+      this.fullscreenLoading = true;
+    },
+    /** 下载模板操作 */
+    importTemplate() {
+      this.$refs['downloadFileForm'].submit()
+    },
+    previewFile(url){
+      window.open(process.env.VUE_APP_BASE_API + url);
+    },
+    submitUpload() {
+      this.$refs.doc.submit();
+      this.doc.open = false;
+      this.doc.fileList = [];
+      this.getFileList();
+    },
+    //附件上传中处理
+    handleFileDocProgress(event, file, fileList) {
+      this.doc.file = file;
+    },
+    //附件上传成功处理
+    handleFileDocSuccess(response, file, fileList) {
+      this.msgSuccess("上传成功");
+      this.doc.open = false;
+      this.doc.fileList = [];
+      this.getFileList();
+    },
+    cancelUpload() {
+      this.doc.open = false;
+      this.doc.fileList = [];
+    },
+    openFileDialog(row) {
+      this.file.open = true
+      this.file.fileList=[];
+      this.file.queryParams.linkId = row.id;
+      this.getFileList();
+    },
+    getFileList() {
+      listFile(this.file.queryParams).then(response => {
+        this.file.fileList = response.rows;
+        this.file.total = response.total;
+      })
+    },
+    handleFileAdd() {
+      this.doc.open = true;
+      this.doc.url = process.env.VUE_APP_BASE_API + "/file/file/uploadFile?linkId=" + this.file.queryParams.linkId + "&linkName=" + this.file.queryParams.linkName;
+    },
+    handleFileRemove(row) {
+      delFile(row.id).then(res => {
+        this.msgSuccess("删除成功");
+        this.getFileList();
+      });
+    },
+    handleRemovePic(file, fileList) {
+      console.log(fileList)
+      this.picUrl = [];
+      for (let fileListElement of fileList) {
+        this.picUrl.push(fileListElement.response.msg)
+      }
+    },
+    handlePicSuccess(res, file, fileList) {
+      this.picUrl.push(res.msg)
+    },
+    /** 查询批文清单列表 */
+    getList() {
+      this.loading = true;
+      listApproval(this.queryParams).then(response => {
+        for (let item of response.rows) {
+          if (item.contentFile) {
+            let contentFile = [];
+            for (let url of item.contentFile.split(',')) {
+              contentFile.push(process.env.VUE_APP_BASE_API + url);
+            }
+            item.contentFile = contentFile;
+          }
+        }
+        this.approvalList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.picUrl = [];
+      this.fileList = [];
+      this.form = {
+        id: null,
+        plantCode: null,
+        division: null,
+        effetivedate: null,
+        itemName: null,
+        itemOverview: null,
+        approvalAttibutes: null,
+        approvalname: null,
+        fileno: null,
+        isInclude: false,
+        responsauth: null,
+        content: null,
+        contentFile: null,
+        scope: null,
+        relatedlaw: null,
+        validityBefore: null,
+        validityAfter: null,
+        isPermanent: null,
+        follow: null,
+        owner: null,
+        reviewer: null,
+        reviewdate: null,
+        isCompliance: null,
+        nextreviewdate: null,
+        remarks: null,
+        delFlag: null,
+        createrCode: null,
+        createdate: null,
+        updaterCode: null,
+        updatedate: null,
+        deptId: null
+      };
+      this.resetForm("form");
+    },
+    /** 导入按钮操作 */
+    handleImport() {
+      this.upload.title = this.$t('用户导入');
+      this.upload.open = true;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加批文清单";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getApproval(id).then(response => {
+        this.form = response.data;
+        if (response.data.contentFile) {
+          this.form.isInclude = true;
+          for (let contentFileElement of response.data.contentFile.split(',')) {
+            let item = {url: process.env.VUE_APP_BASE_API + contentFileElement, response: {msg: contentFileElement}}
+            this.fileList.push(item);
+            this.picUrl.push(contentFileElement);
+          }
+        }
+        this.open = true;
+        this.title = "修改批文清单";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.picUrl.length > 0) {
+            this.form.contentFile = this.picUrl.join(',')
+          }
+          if (this.form.id != null) {
+            updateApproval(this.form).then(response => {
+              this.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addApproval(this.form).then(response => {
+              this.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$confirm('是否确认删除数据项?').then(function () {
+        return delApproval(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {
+      });
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      const queryParams = this.queryParams;
+      this.$confirm(this.$t('是否确认导出所有批文清单数据项?'), this.$t('警告'), {
+        confirmButtonText: this.$t('确定'),
+        cancelButtonText: this.$t('取消'),
+        type: "warning"
+      }).then(function () {
+        return exportApproval(queryParams);
+      }).then(response => {
+        this.download(response.msg);
+      })
+    },
+    handleFileView(row){
+      this.$router.push({ path: '/ehs/edit', query: { fileId: row.id, ot: 'detail' }});
+    }
+  }
+};
+</script>

+ 1 - 1
ui/src/views/register.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="register">
     <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
-      <h3 class="title">若依后台管理系统</h3>
+      <h3 class="title">CPMS管理系统</h3>
       <el-form-item prop="username">
         <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
           <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />