فهرست منبع

onlyoffice 优化

Li Yuan 1 سال پیش
والد
کامیت
a9bcf09c50
99فایلهای تغییر یافته به همراه6796 افزوده شده و 0 حذف شده
  1. 35 0
      ibps-provider-root/modules/provider-business/pom.xml
  2. 32 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/IntegrationApplication.java
  3. 87 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/IntegrationConfiguration.java
  4. 264 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/controllers/EditorController.java
  5. 654 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/controllers/FileController.java
  6. 143 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/controllers/IndexController.java
  7. 32 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Callback.java
  8. 50 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/CallbackHandler.java
  9. 35 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Status.java
  10. 59 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/EditCallback.java
  11. 50 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/ForcesaveCallback.java
  12. 50 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/SaveCallback.java
  13. 29 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/CallbackManager.java
  14. 352 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/DefaultCallbackManager.java
  15. 247 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DefaultDocumentManager.java
  16. 42 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DocumentManager.java
  17. 341 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/history/DefaultHistoryManager.java
  18. 26 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/history/HistoryManager.java
  19. 131 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/DefaultJwtManager.java
  20. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/JwtManager.java
  21. 70 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/template/SampleTemplateManager.java
  22. 29 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/template/TemplateManager.java
  23. 24 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/AbstractModel.java
  24. 36 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/Format.java
  25. 52 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Customization.java
  26. 40 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Embedded.java
  27. 48 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Goback.java
  28. 45 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Info.java
  29. 18 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Plugins.java
  30. 32 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Action.java
  31. 48 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/ConvertErrorType.java
  32. 25 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/DocumentType.java
  33. 24 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Mode.java
  34. 24 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/ToolbarDocked.java
  35. 25 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Type.java
  36. 41 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/CommentGroup.java
  37. 49 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Document.java
  38. 61 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/EditorConfig.java
  39. 44 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/FileModel.java
  40. 55 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Permission.java
  41. 43 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/ReferenceData.java
  42. 32 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Template.java
  43. 46 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/User.java
  44. 23 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/serializers/FilterState.java
  45. 38 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/serializers/SerializerFilter.java
  46. 43 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/storage/FileStorageMutator.java
  47. 31 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/storage/FileStoragePathBuilder.java
  48. 388 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/storage/LocalFileStorage.java
  49. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/Constants.java
  50. 36 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/Misc.java
  51. 72 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/SSLUtils.java
  52. 167 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/file/DefaultFileUtility.java
  53. 41 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/file/FileUtility.java
  54. 103 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/DefaultFormatService.java
  55. 265 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/DefaultServiceConverter.java
  56. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/FormatService.java
  57. 35 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/ServiceConverter.java
  58. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Action.java
  59. 31 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ChangesHistory.java
  60. 31 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ChangesUser.java
  61. 40 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Convert.java
  62. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ConvertedData.java
  63. 36 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Converter.java
  64. 40 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/History.java
  65. 31 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Mentions.java
  66. 32 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Protect.java
  67. 37 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Reference.java
  68. 31 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ReferenceData.java
  69. 34 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Rename.java
  70. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Restore.java
  71. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/SaveAs.java
  72. 47 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Track.java
  73. 33 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/UserInfo.java
  74. 41 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/AbstractEntity.java
  75. 39 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/Group.java
  76. 56 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/Permission.java
  77. 45 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/User.java
  78. 58 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/AbstractMapper.java
  79. 27 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/Mapper.java
  80. 69 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/PermissionsMapper.java
  81. 53 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/UsersMapper.java
  82. 62 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/GroupServices.java
  83. 62 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/PermissionServices.java
  84. 93 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/UserServices.java
  85. 23 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/Configurer.java
  86. 25 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/CustomizationConfigurer.java
  87. 25 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/DocumentConfigurer.java
  88. 25 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/EditorConfigConfigurer.java
  89. 25 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/EmbeddedConfigurer.java
  90. 26 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/FileConfigurer.java
  91. 38 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultCustomizationConfigurer.java
  92. 93 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultDocumentConfigurer.java
  93. 112 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultEditorConfigConfigurer.java
  94. 61 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultEmbeddedConfigurer.java
  95. 137 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultFileConfigurer.java
  96. 31 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultCustomizationWrapper.java
  97. 34 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultDocumentWrapper.java
  98. 30 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultEmbeddedWrapper.java
  99. 40 0
      ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultFileWrapper.java

+ 35 - 0
ibps-provider-root/modules/provider-business/pom.xml

@@ -37,6 +37,41 @@
 			<artifactId>core</artifactId>
 			<version>3.3.3</version>
 		</dependency>
+
+		<dependency>
+			<groupId>com.googlecode.json-simple</groupId>
+			<artifactId>json-simple</artifactId>
+			<version>1.1</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.code.gson</groupId>
+			<artifactId>gson</artifactId>
+			<version>2.8.9</version>
+		</dependency>
+		<dependency>
+			<groupId>com.inversoft</groupId>
+			<artifactId>prime-jwt</artifactId>
+			<version>1.3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+			<version>1.18.20</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-core</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.modelmapper</groupId>
+			<artifactId>modelmapper</artifactId>
+			<version>2.4.2</version>
+		</dependency>
 		<!--  阿里云短信
         <dependency>
             <groupId>com.aliyun</groupId>

+ 32 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/IntegrationApplication.java

@@ -0,0 +1,32 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class IntegrationApplication {
+
+    // run the SpringApplication from the IntagrationApplication with the specified parameters
+    public static void main(final String[] args) {
+        SpringApplication.run(IntegrationApplication.class, args);
+    }
+
+}

+ 87 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/IntegrationConfiguration.java

@@ -0,0 +1,87 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.documentserver.util.SSLUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.json.simple.parser.JSONParser;
+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 IntegrationConfiguration {
+
+    @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.isBlank(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();
+    }
+}

+ 264 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/controllers/EditorController.java

@@ -0,0 +1,264 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.controllers;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
+import com.onlyoffice.integration.documentserver.models.enums.Action;
+import com.onlyoffice.integration.documentserver.models.enums.Type;
+import com.onlyoffice.integration.documentserver.models.filemodel.FileModel;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.dto.Mentions;
+import com.onlyoffice.integration.dto.Protect;
+import com.onlyoffice.integration.dto.UserInfo;
+import com.onlyoffice.integration.entities.User;
+import com.onlyoffice.integration.services.UserServices;
+import com.onlyoffice.integration.services.configurers.FileConfigurer;
+import com.onlyoffice.integration.services.configurers.wrappers.DefaultFileWrapper;
+import lombok.SneakyThrows;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+import static com.onlyoffice.integration.documentserver.util.Constants.ANONYMOUS_USER_ID;
+
+@CrossOrigin("*")
+@RequestMapping("/onlyOffice")
+@RestController
+public class EditorController {
+
+    @Value("${files.docservice.url.site}")
+    private String docserviceSite;
+
+    @Value("${files.docservice.url.api}")
+    private String docserviceApiUrl;
+
+    @Value("${files.docservice.languages}")
+    private String langs;
+
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+
+    @Autowired
+    private JwtManager jwtManager;
+
+    @Autowired
+    private UserServices userService;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Autowired
+    private FileConfigurer<DefaultFileWrapper> fileConfigurer;
+
+    @GetMapping(path = "${url.editor}")
+    // process request to open the editor page
+    public String index(@RequestParam("fileName") final String fileName,
+                        @RequestParam(value = "action", required = false) final String actionParam,
+                        @RequestParam(value = "type", required = false) final String typeParam,
+                        @RequestParam(value = "actionLink", required = false) final String actionLink,
+                        @RequestParam(value = "directUrl", required = false,
+                                defaultValue = "false") final Boolean directUrl,
+                        @CookieValue(value = "uid") final String uid,
+                        @CookieValue(value = "ulang") final String lang,
+                        final Model model) throws JsonProcessingException {
+        Action action = Action.edit;
+        Type type = Type.desktop;
+        Locale locale = new Locale("en");
+
+        if (actionParam != null) {
+            action = Action.valueOf(actionParam);
+        }
+        if (typeParam != null) {
+            type = Type.valueOf(typeParam);
+        }
+
+        List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
+        for (String langAndKey : langsAndKeys) {
+            String[] couple = langAndKey.split(":");
+            if (couple[0].equals(lang)) {
+                String[] langAndCountry = couple[0].split("-");
+                locale = new Locale(langAndCountry[0], langAndCountry.length > 1 ? langAndCountry[1] : "");
+            }
+        }
+
+        Optional<User> optionalUser = userService.findUserById(Integer.parseInt(uid));
+
+        // if the user is not present, return the ONLYOFFICE start page
+        if (!optionalUser.isPresent()) {
+            return "index.html";
+        }
+
+        User user = optionalUser.get();
+        user.setImage(user.getAvatar() ? storagePathBuilder.getServerUrl(true) + "/css/img/uid-"
+                + user.getId() + ".png" : null);
+
+        // get file model with the default file parameters
+        FileModel fileModel = fileConfigurer.getFileModel(
+                DefaultFileWrapper
+                        .builder()
+                        .fileName(fileName)
+                        .type(type)
+                        .lang(locale.toLanguageTag())
+                        .action(action)
+                        .user(user)
+                        .actionData(actionLink)
+                        .isEnableDirectUrl(directUrl)
+                        .build()
+        );
+
+        // add attributes to the specified model
+        // add file model with the default parameters to the original model
+        model.addAttribute("model", fileModel);
+
+        // create the document service api URL and add it to the model
+        model.addAttribute("docserviceApiUrl", docserviceSite + docserviceApiUrl);
+
+        // get an image and add it to the model
+        model.addAttribute("dataInsertImage",  getInsertImage(directUrl));
+
+        // get a document for comparison and add it to the model
+        model.addAttribute("dataDocument",  getCompareFile(directUrl));
+
+        // get recipients data for mail merging and add it to the model
+        model.addAttribute("dataSpreadsheet", getSpreadsheet(directUrl));
+
+        // get user data for mentions and add it to the model
+        model.addAttribute("usersForMentions", getUserMentions(uid));
+
+        model.addAttribute("usersInfo", getUsersInfo(uid));
+
+        // get user data for protect and add it to the model
+        model.addAttribute("usersForProtect", getUserProtect(uid));
+
+        return "editor.html";
+    }
+
+    private List<Mentions> getUserMentions(final String uid) {  // get user data for mentions
+        List<Mentions> usersForMentions = new ArrayList<>();
+        if (uid != null && !uid.equals("4")) {
+            List<User> list = userService.findAll();
+            for (User u : list) {
+                if (u.getId() != Integer.parseInt(uid) && u.getId() != ANONYMOUS_USER_ID) {
+
+                    // user data includes user names and emails
+                    usersForMentions.add(new Mentions(u.getName(), u.getEmail()));
+                }
+            }
+        }
+
+        return usersForMentions;
+    }
+
+    private List<UserInfo> getUsersInfo(final String uid) {  // get user data for mentions
+        List<UserInfo> usersInfo = new ArrayList<>();
+        if (uid != null && !uid.equals("4")) {
+            List<User> list = userService.findAll();
+            for (User u : list) {
+                String image = u.getAvatar() ? storagePathBuilder.getServerUrl(true) + "/css/img/uid-"
+                + u.getId() + ".png" : null;
+                usersInfo.add(new UserInfo(u.getId(), u.getName(), u.getEmail(), image));
+            }
+        }
+        return usersInfo;
+    }
+
+    private List<Protect> getUserProtect(final String uid) {  // get user data for protect
+        List<Protect> usersForProtect = new ArrayList<>();
+        if (uid != null && !uid.equals("4")) {
+            List<User> list = userService.findAll();
+            for (User u : list) {
+                if (u.getId() != Integer.parseInt(uid) && u.getId() != ANONYMOUS_USER_ID) {
+
+                    // user data includes user names, IDs and emails
+                    usersForProtect.add(new Protect(u.getId(), u.getName(), u.getEmail()));
+                }
+            }
+        }
+
+        return usersForProtect;
+    }
+
+
+    @SneakyThrows
+    private String getInsertImage(final Boolean directUrl) {  // get an image that will be inserted into the document
+        Map<String, Object> dataInsertImage = new HashMap<>();
+        dataInsertImage.put("fileType", "png");
+        dataInsertImage.put("url", storagePathBuilder.getServerUrl(true) + "/css/img/logo.png");
+        if (directUrl) {
+            dataInsertImage.put("directUrl", storagePathBuilder
+                    .getServerUrl(false) + "/css/img/logo.png");
+        }
+
+        // check if the document token is enabled
+        if (jwtManager.tokenEnabled()) {
+
+            // create token from the dataInsertImage object
+            dataInsertImage.put("token", jwtManager.createToken(dataInsertImage));
+        }
+
+        return objectMapper.writeValueAsString(dataInsertImage)
+                .substring(1, objectMapper.writeValueAsString(dataInsertImage).length() - 1);
+    }
+
+    // get a document that will be compared with the current document
+    @SneakyThrows
+    private String getCompareFile(final Boolean directUrl) {
+        Map<String, Object> dataDocument = new HashMap<>();
+        dataDocument.put("fileType", "docx");
+        dataDocument.put("url", storagePathBuilder.getServerUrl(true) + "/assets?name=sample.docx");
+        if (directUrl) {
+            dataDocument.put("directUrl", storagePathBuilder
+                    .getServerUrl(false) + "/assets?name=sample.docx");
+        }
+
+        // check if the document token is enabled
+        if (jwtManager.tokenEnabled()) {
+
+            // create token from the dataDocument object
+            dataDocument.put("token", jwtManager.createToken(dataDocument));
+        }
+
+        return objectMapper.writeValueAsString(dataDocument);
+    }
+
+    @SneakyThrows
+    private String getSpreadsheet(final Boolean directUrl) {
+        Map<String, Object> dataSpreadsheet = new HashMap<>();  // get recipients data for mail merging
+        dataSpreadsheet.put("fileType", "csv");
+        dataSpreadsheet.put("url", storagePathBuilder.getServerUrl(true) + "/csv");
+        if (directUrl) {
+            dataSpreadsheet.put("directUrl", storagePathBuilder.getServerUrl(false) + "/csv");
+        }
+
+        // check if the document token is enabled
+        if (jwtManager.tokenEnabled()) {
+
+            // create token from the dataSpreadsheet object
+            dataSpreadsheet.put("token", jwtManager.createToken(dataSpreadsheet));
+        }
+
+        return objectMapper.writeValueAsString(dataSpreadsheet);
+    }
+}

+ 654 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/controllers/FileController.java

@@ -0,0 +1,654 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.controllers;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.onlyoffice.integration.documentserver.callbacks.CallbackHandler;
+import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
+import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
+import com.onlyoffice.integration.documentserver.managers.history.HistoryManager;
+import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
+import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
+import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
+import com.onlyoffice.integration.dto.*;
+import com.onlyoffice.integration.entities.User;
+import com.onlyoffice.integration.services.UserServices;
+import org.apache.commons.lang3.StringUtils;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.util.UriComponents;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.*;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@CrossOrigin("*")
+@RequestMapping("/onlyOffice")
+@RestController
+public class FileController {
+
+    @Value("${files.docservice.header}")
+    private String documentJwtHeader;
+
+    @Value("${filesize-max}")
+    private String filesizeMax;
+
+    @Value("${files.docservice.url.site}")
+    private String docserviceUrlSite;
+
+    @Value("${files.docservice.url.command}")
+    private String docserviceUrlCommand;
+
+    @Autowired
+    private FileUtility fileUtility;
+    @Autowired
+    private DocumentManager documentManager;
+    @Autowired
+    private JwtManager jwtManager;
+    @Autowired
+    private FileStorageMutator storageMutator;
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+    @Autowired
+    private UserServices userService;
+    @Autowired
+    private CallbackHandler callbackHandler;
+    @Autowired
+    private ObjectMapper objectMapper;
+    @Autowired
+    private ServiceConverter serviceConverter;
+    @Autowired
+    private CallbackManager callbackManager;
+    @Autowired
+    private HistoryManager historyManager;
+
+    // create user metadata
+    private String createUserMetadata(final String uid, final String fullFileName) {
+        Optional<User> optionalUser = userService.findUserById(Integer.parseInt(uid));  // find a user by their ID
+        String documentType = fileUtility.getDocumentType(fullFileName).toString().toLowerCase();  // get document type
+        if (optionalUser.isPresent()) {
+            User user = optionalUser.get();
+            storageMutator.createMeta(fullFileName,  // create meta information with the user ID and name specified
+                    String.valueOf(user.getId()), user.getName());
+        }
+        return "{ \"filename\": \"" + fullFileName + "\", \"documentType\": \"" + documentType + "\" }";
+    }
+
+    // download data from the specified file
+    private ResponseEntity<Resource> downloadFile(final String fileName) {
+        Resource resource = storageMutator.loadFileAsResource(fileName);  // load the specified file as a resource
+        String contentType = "application/octet-stream";
+
+        // create a response with the content type, header and body with the file data
+        return ResponseEntity.ok()
+                .contentType(MediaType.parseMediaType(contentType))
+                .header(HttpHeaders.CONTENT_DISPOSITION,
+                        "attachment; filename=\"" + resource.getFilename() + "\"")
+                .body(resource);
+    }
+
+    private ResponseEntity<Resource> downloadSample(final String fileName) {
+        String serverPath = System.getProperty("user.dir");
+        String contentType = "application/octet-stream";
+        String[] fileLocation = new String[] {serverPath, "src", "main", "resources", "assets", "document-templates",
+                                              "sample", fileName};
+        Path filePath = Paths.get(String.join(File.separator, fileLocation));
+        Resource resource;
+        try {
+            resource = new UrlResource(filePath.toUri());
+            if (resource.exists()) {
+                return ResponseEntity.ok()
+                        .contentType(MediaType.parseMediaType(contentType))
+                        .header(HttpHeaders.CONTENT_DISPOSITION,
+                                "attachment; filename=\"" + resource.getFilename() + "\"")
+                        .body(resource);
+        }
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    // download data from the specified history file
+    private ResponseEntity<Resource> downloadFileHistory(final String fileName,
+                                                         final String version,
+                                                         final String file) {
+
+        // load the specified file as a resource
+        Resource resource = storageMutator.loadFileAsResourceHistory(fileName, version, file);
+        String contentType = "application/octet-stream";
+
+        // create a response with the content type, header and body with the file data
+        return ResponseEntity.ok()
+                .contentType(MediaType.parseMediaType(contentType))
+                .header(HttpHeaders.CONTENT_DISPOSITION,
+                        "attachment; filename=\"" + resource.getFilename() + "\"")
+                .body(resource);
+    }
+
+    @PostMapping("/upload")
+    @ResponseBody
+    public String upload(@RequestParam("file") final MultipartFile file,  // upload a file
+                             @CookieValue("uid") final String uid) {
+        try {
+            String fullFileName = file.getOriginalFilename();  // get file name
+            String fileExtension = fileUtility.getFileExtension(fullFileName);  // get file extension
+            long fileSize = file.getSize();  // get file size
+            byte[] bytes = file.getBytes();  // get file in bytes
+
+            // check if the file size exceeds the maximum file size or is less than 0
+            if (fileUtility.getMaxFileSize() < fileSize || fileSize <= 0) {
+                return "{ \"error\": \"File size is incorrect\"}";  // if so, write an error message to the response
+            }
+
+            // check if file extension is supported by the editor
+            if (!fileUtility.getFileExts().contains(fileExtension)) {
+
+                // if not, write an error message to the response
+                return "{ \"error\": \"File type is not supported\"}";
+            }
+
+            String fileNamePath = storageMutator.updateFile(fullFileName, bytes);  // update a file
+            if (StringUtils.isBlank(fileNamePath)) {
+                throw new IOException("Could not update a file");  // if the file cannot be updated, an error occurs
+            }
+
+            fullFileName = fileUtility.getFileNameWithoutExtension(fileNamePath)
+                    + "." + fileExtension;  // get full file name
+
+            return createUserMetadata(uid, fullFileName);  // create user metadata and return it
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        // if the operation of file uploading is unsuccessful, an error occurs
+        return "{ \"error\": \"Something went wrong when uploading the file.\"}";
+    }
+
+    @PostMapping(path = "${url.converter}")
+    @ResponseBody
+    public String convert(@RequestBody final Converter body,  // convert a file
+                          @CookieValue("uid") final String uid, @CookieValue("ulang") final String lang) {
+        // get file name
+        String fileName = body.getFileName();
+
+        // get URL for downloading a file with the specified name
+        String fileUri = documentManager.getDownloadUrl(fileName, true);
+
+        // get file password if it exists
+        String filePass = body.getFilePass() != null ? body.getFilePass() : null;
+
+        // get file extension
+        String fileExt = fileUtility.getFileExtension(fileName);
+
+        // get document type (word, cell or slide)
+        DocumentType type = fileUtility.getDocumentType(fileName);
+
+        // convert to .ooxml
+        String internalFileExt = "ooxml";
+
+        try {
+            // check if the file with such an extension can be converted
+            if (fileUtility.getConvertExts().contains(fileExt)) {
+                String key = serviceConverter.generateRevisionId(fileUri);  // generate document key
+                ConvertedData response = serviceConverter  // get the URL to the converted file
+                        .getConvertedData(fileUri, fileExt, internalFileExt, key, filePass, true, lang);
+
+                String newFileUri = response.getUri();
+                String newFileType = "." + response.getFileType();
+
+                if (newFileUri.isEmpty()) {
+                    return "{ \"step\" : \"0\", \"filename\" : \"" + fileName + "\"}";
+                }
+
+                /* get a file name of an internal file extension with an index if the file
+                 with such a name already exists */
+                String nameWithInternalExt = fileUtility.getFileNameWithoutExtension(fileName) + newFileType;
+                String correctedName = documentManager.getCorrectName(nameWithInternalExt);
+
+                URL url = new URL(newFileUri);
+                java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+                InputStream stream = connection.getInputStream();  // get input stream of the converted file
+
+                if (stream == null) {
+                    connection.disconnect();
+                    throw new RuntimeException("Input stream is null");
+                }
+
+                // remove source file
+                storageMutator.deleteFile(fileName);
+
+                // create the converted file with input stream
+                storageMutator.createFile(FileSystems.getDefault().getPath(storagePathBuilder.getFileLocation(correctedName)), stream);
+                fileName = correctedName;
+            }
+
+            // create meta information about the converted file with the user ID and name specified
+            return createUserMetadata(uid, fileName);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        // if the operation of file converting is unsuccessful, an error occurs
+        return "{ \"error\": \"" + "The file can't be converted.\"}";
+    }
+
+    @PostMapping("/delete")
+    @ResponseBody
+    public String delete(@RequestBody final Converter body) {  // delete a file
+        try {
+            String fullFileName = fileUtility.getFileName(body.getFileName());  // get full file name
+
+            // delete a file from the storage and return the status of this operation (true or false)
+            boolean fileSuccess = storageMutator.deleteFile(fullFileName);
+
+            // delete file history and return the status of this operation (true or false)
+            boolean historySuccess = storageMutator.deleteFileHistory(fullFileName);
+
+            return "{ \"success\": \"" + (fileSuccess && historySuccess) + "\"}";
+        } catch (Exception e) {
+            // if the operation of file deleting is unsuccessful, an error occurs
+            return "{ \"error\": \"" + e.getMessage() + "\"}";
+        }
+    }
+
+    @GetMapping("/downloadhistory")
+    public ResponseEntity<Resource> downloadHistory(final HttpServletRequest request, // download a file
+                                             @RequestParam("fileName") final String fileName,
+                                             @RequestParam("ver") final String version,
+                                             @RequestParam("file") final String file) { // history file
+        try {
+            // check if a token is enabled or not
+            if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) {
+                String header = request.getHeader(documentJwtHeader == null  // get the document JWT header
+                        || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
+                if (header != null && !header.isEmpty()) {
+                    String token = header
+                            .replace("Bearer ", "");  // token is the header without the Bearer prefix
+                    jwtManager.readToken(token);  // read the token
+                } else {
+                    return null;
+                }
+            }
+            return downloadFileHistory(fileName, version, file);  // download data from the specified file
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    @GetMapping(path = "${url.download}")
+    public ResponseEntity<Resource> download(final HttpServletRequest request,  // download a file
+                                             @RequestParam("fileName") final String fileName,
+                                             @RequestParam(value = "userAddress", required = false)
+                                                 final String userAddress) {
+        try {
+            // check if a token is enabled or not
+            if (jwtManager.tokenEnabled() && userAddress != null && jwtManager.tokenUseForRequest()) {
+                String header = request.getHeader(documentJwtHeader == null // get the document JWT header
+                        || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
+                if (header != null && !header.isEmpty()) {
+                    String token = header
+                            .replace("Bearer ", "");  // token is the header without the Bearer prefix
+                    jwtManager.readToken(token);  // read the token
+                } else {
+                    return null;
+                }
+            }
+            return downloadFile(fileName);  // download data from the specified file
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    @GetMapping("/create")
+    public String create(@RequestParam("fileExt")
+                             final String fileExt, // create a sample file of the specified extension
+                         @RequestParam(value = "sample", required = false) final Optional<Boolean> isSample,
+                         @CookieValue(value = "uid", required = false) final String uid,
+                         final Model model) {
+        // specify if the sample data exists or not
+        Boolean sampleData = isSample.isPresent() && isSample.get();
+        if (fileExt != null) {
+            try {
+                Optional<User> user = userService.findUserById(Integer.parseInt(uid));  // find a user by their ID
+                if (!user.isPresent()) {
+                    // if the user with the specified ID doesn't exist, an error occurs
+                    throw new RuntimeException("Could not fine any user with id = " + uid);
+                }
+                String fileName = documentManager.createDemo(fileExt,
+                        sampleData,
+                        uid,
+                        user.get().getName());  // create a demo document with the sample data
+                if (StringUtils.isBlank(fileName) || fileName == null) {
+                    throw new RuntimeException("You must have forgotten to add asset files");
+                }
+                return "redirect:editor?fileName=" + URLEncoder
+                        .encode(fileName, "UTF-8");  // redirect the request
+            } catch (Exception ex) {
+                model.addAttribute("error", ex.getMessage());
+                return "error.html";
+            }
+        }
+        return "redirect:/";
+    }
+
+    @GetMapping("/assets")
+    public ResponseEntity<Resource> assets(@RequestParam("name")
+                                               final String name) {  // get sample files from the assests
+        return downloadSample(name);
+    }
+
+    @GetMapping("/csv")
+    public ResponseEntity<Resource> csv() {  // download a csv file
+        return downloadSample("csv.csv");
+    }
+
+    @GetMapping("/files")
+    @ResponseBody
+    public ArrayList<Map<String, Object>> files(@RequestParam(value = "fileId", required = false)
+                                                    final String fileId) {  // get files information
+        return fileId == null ? documentManager.getFilesInfo() : documentManager.getFilesInfo(fileId);
+    }
+
+    @PostMapping(path = "${url.track}")
+    @ResponseBody
+    public String track(final HttpServletRequest request,  // track file changes
+                        @RequestParam("fileName") final String fileName,
+                        @RequestParam("userAddress") final String userAddress,
+                        @RequestBody final Track body) {
+        Track track;
+        try {
+            String bodyString = objectMapper
+                    .writeValueAsString(body);  // write the request body to the object mapper as a string
+            String header = request.getHeader(documentJwtHeader == null  // get the request header
+                    || documentJwtHeader.isEmpty() ? "Authorization" : documentJwtHeader);
+
+            if (bodyString.isEmpty()) {  // if the request body is empty, an error occurs
+                throw new RuntimeException("{\"error\":1,\"message\":\"Request payload is empty\"}");
+            }
+
+            JSONObject bodyCheck = jwtManager.parseBody(bodyString, header);  // parse the request body
+            track = objectMapper.readValue(bodyCheck.toJSONString(), Track.class);  // read the request body
+        } catch (Exception e) {
+            e.printStackTrace();
+            return e.getMessage();
+        }
+
+        int error = callbackHandler.handle(track, fileName);
+
+        return "{\"error\":" + error + "}";
+    }
+
+    @PostMapping("/saveas")
+    @ResponseBody
+    public String saveAs(@RequestBody final SaveAs body, @CookieValue("uid") final String uid) {
+        try {
+            String fileName = documentManager.getCorrectName(body.getTitle());
+            String curExt = fileUtility.getFileExtension(fileName);
+
+            if (!fileUtility.getFileExts().contains(curExt)) {
+                return "{\"error\":\"File type is not supported\"}";
+            }
+
+            URL url = new URL(body.getUrl());
+            java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
+            InputStream stream = connection.getInputStream();
+
+            if (Integer.parseInt(filesizeMax) < stream.available() || stream.available() <= 0) {
+                return "{\"error\":\"File size is incorrect\"}";
+            }
+            storageMutator.createFile(FileSystems.getDefault().getPath(storagePathBuilder.getFileLocation(fileName)), stream);
+            createUserMetadata(uid, fileName);
+
+            return "{\"file\":  \"" + fileName + "\"}";
+        } catch (IOException e) {
+            e.printStackTrace();
+            return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}";
+        }
+    }
+
+    @PostMapping("/rename")
+    @ResponseBody
+    public String rename(@RequestBody final Rename body) {
+        String fileName = body.getFileName();
+
+        HashMap<String, String> meta = new HashMap<>();
+        meta.put("title", fileName + "." + body.getFileType());
+
+        try {
+            callbackManager.commandRequest("meta", body.getFileKey(), meta);
+            return "result ok";
+        } catch (Exception e) {
+            e.printStackTrace();
+            return e.getMessage();
+        }
+    }
+
+    @PostMapping("/reference")
+    @ResponseBody
+    public String reference(@RequestBody final Reference body) {
+        try {
+            JSONParser parser = new JSONParser();
+            Gson gson = new GsonBuilder().disableHtmlEscaping().create();
+
+            String userAddress = "";
+            String fileName = "";
+
+            if (body.getReferenceData() != null) {
+                ReferenceData referenceData = body.getReferenceData();
+
+                if (referenceData.getInstanceId().equals(storagePathBuilder.getServerUrl(false))) {
+                    JSONObject fileKey = (JSONObject) parser.parse(referenceData.getFileKey());
+                    userAddress = (String) fileKey.get("userAddress");
+                    if (userAddress.equals(InetAddress.getLocalHost().getHostAddress())) {
+                        fileName = (String) fileKey.get("fileName");
+                    }
+                }
+            }
+
+            String link = body.getLink();
+            if (fileName.equals("") && link != null) {
+                if (!link.contains(storagePathBuilder.getServerUrl(true))) {
+                    HashMap<String, String> data = new HashMap<>();
+                    data.put("url", link);
+                    data.put("directUrl", link);
+                    return gson.toJson(data);
+                }
+
+                UriComponents uriComponents = UriComponentsBuilder.fromUriString(body.getLink()).build();
+                fileName = uriComponents.getQueryParams().getFirst("fileName");
+                boolean fileExists = new File(storagePathBuilder.getFileLocation(fileName)).exists();
+                if (!fileExists) {
+                    return "{ \"error\": \"File is not exist\"}";
+                }
+            }
+
+            if (fileName.equals("")) {
+                try {
+                    String path = (String) body.getPath();
+                    path = fileUtility.getFileName(path);
+                    File f = new File(storagePathBuilder.getFileLocation(path));
+                    if (f.exists()) {
+                        fileName = path;
+                    }
+                } catch (Exception e) {
+                    return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}";
+                }
+            }
+
+            if (fileName.equals("")) {
+                return "{ \"error\": \"File not found\"}";
+            }
+
+            HashMap<String, Object> fileKey = new HashMap<>();
+            fileKey.put("fileName", fileName);
+            fileKey.put("userAddress", InetAddress.getLocalHost().getHostAddress());
+
+            HashMap<String, Object> referenceData = new HashMap<>();
+            referenceData.put("instanceId", storagePathBuilder.getServerUrl(true));
+            referenceData.put("fileKey", gson.toJson(fileKey));
+
+            HashMap<String, Object> data = new HashMap<>();
+            data.put("fileType", fileUtility.getFileExtension(fileName));
+            data.put("key", serviceConverter.generateRevisionId(
+                storagePathBuilder.getStorageLocation()
+                + "/" + fileName + "/"
+                + new File(storagePathBuilder.getFileLocation(fileName)).lastModified()
+                ));
+            data.put("url", documentManager.getDownloadUrl(fileName, true));
+            data.put("directUrl", body.getDirectUrl() ? documentManager.getDownloadUrl(fileName, false) : null);
+            data.put("referenceData", referenceData);
+            data.put("path", fileName);
+            data.put("link", storagePathBuilder.getServerUrl(true) + "/editor?fileName=" + fileName);
+
+            if (jwtManager.tokenEnabled()) {
+                String token = jwtManager.createToken(data);
+                data.put("token", token);
+            }
+            return gson.toJson(data);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "{ \"error\" : 1, \"message\" : \"" + e.getMessage() + "\"}";
+        }
+    }
+
+    @GetMapping("/history")
+    @ResponseBody
+    public String history(@RequestParam("fileName") final String fileName) {
+        return historyManager.getHistory(fileName);
+    }
+
+    @GetMapping("/historydata")
+    @ResponseBody
+    public String history(@RequestParam("fileName") final String fileName,
+                          @RequestParam("version") final String version,
+                          @RequestParam(value = "directUrl", defaultValue = "false") final Boolean directUrl) {
+        return historyManager.getHistoryData(fileName, version, directUrl);
+    }
+
+    @PutMapping("/restore")
+    @ResponseBody
+    public String restore(@RequestBody final Restore body, @CookieValue("uid") final Integer uid) {
+        try {
+            String sourceStringFile = storagePathBuilder.getFileLocation(body.getFileName());
+            File sourceFile = new File(sourceStringFile);
+            Path sourcePathFile = sourceFile.toPath();
+            String historyDirectory = storagePathBuilder.getHistoryDir(sourcePathFile.toString());
+
+            Integer bumpedVersion = storagePathBuilder.getFileVersion(historyDirectory, false);
+            String bumpedVersionStringDirectory = documentManager.versionDir(historyDirectory, bumpedVersion, true);
+            File bumpedVersionDirectory = new File(bumpedVersionStringDirectory);
+            if (!bumpedVersionDirectory.exists()) {
+                bumpedVersionDirectory.mkdir();
+            }
+
+            Path bumpedKeyPathFile = Paths.get(bumpedVersionStringDirectory, "key.txt");
+            String bumpedKeyStringFile = bumpedKeyPathFile.toString();
+            File bumpedKeyFile = new File(bumpedKeyStringFile);
+            String bumpedKey = serviceConverter.generateRevisionId(
+                storagePathBuilder.getStorageLocation()
+                + "/"
+                + body.getFileName()
+                + "/"
+                + Long.toString(sourceFile.lastModified())
+            );
+            FileWriter bumpedKeyFileWriter = new FileWriter(bumpedKeyFile);
+            bumpedKeyFileWriter.write(bumpedKey);
+            bumpedKeyFileWriter.close();
+
+            User user = userService.findUserById(uid).get();
+
+            Path bumpedChangesPathFile = Paths.get(bumpedVersionStringDirectory, "changes.json");
+            String bumpedChangesStringFile = bumpedChangesPathFile.toString();
+            File bumpedChangesFile = new File(bumpedChangesStringFile);
+            JSONObject bumpedChangesUser = new JSONObject();
+            // Don't add the `uid-` prefix.
+            // https://github.com/ONLYOFFICE/document-server-integration/issues/437#issuecomment-1663526562
+            bumpedChangesUser.put("id", user.getId());
+            bumpedChangesUser.put("name", user.getName());
+            JSONObject bumpedChangesChangesItem = new JSONObject();
+            bumpedChangesChangesItem.put("created", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+            bumpedChangesChangesItem.put("user", bumpedChangesUser);
+            JSONArray bumpedChangesChanges = new JSONArray();
+            bumpedChangesChanges.add(bumpedChangesChangesItem);
+            JSONObject bumpedChanges = new JSONObject();
+            bumpedChanges.put("serverVersion", null);
+            bumpedChanges.put("changes", bumpedChangesChanges);
+            String bumpedChangesContent = bumpedChanges.toJSONString();
+            FileWriter bumpedChangesFileWriter = new FileWriter(bumpedChangesFile);
+            bumpedChangesFileWriter.write(bumpedChangesContent);
+            bumpedChangesFileWriter.close();
+
+            String sourceExtension = fileUtility.getFileExtension(body.getFileName());
+            String previousBasename = "prev." + sourceExtension;
+
+            Path bumpedFile = Paths.get(bumpedVersionStringDirectory, previousBasename);
+            Files.move(sourcePathFile, bumpedFile);
+
+            String recoveryVersionStringDirectory = documentManager.versionDir(
+                    historyDirectory,
+                    body.getVersion(),
+                    true
+            );
+            Path recoveryPathFile = Paths.get(recoveryVersionStringDirectory, previousBasename);
+            String recoveryStringFile = recoveryPathFile.toString();
+            FileInputStream recoveryStream = new FileInputStream(recoveryStringFile);
+            storageMutator.createFile(sourcePathFile, recoveryStream);
+            recoveryStream.close();
+
+            JSONObject responseBody = new JSONObject();
+            responseBody.put("error", null);
+            responseBody.put("success", true);
+            return responseBody.toJSONString();
+        } catch (Exception error) {
+            error.printStackTrace();
+            JSONObject responseBody = new JSONObject();
+            responseBody.put("error", error.getMessage());
+            responseBody.put("success", false);
+            return responseBody.toJSONString();
+        }
+    }
+}

+ 143 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/controllers/IndexController.java

@@ -0,0 +1,143 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.controllers;
+
+import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.documentserver.util.Misc;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.entities.User;
+import com.onlyoffice.integration.services.UserServices;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@CrossOrigin("*")
+@RequestMapping("/onlyOffice")
+@RestController
+public class IndexController {
+
+    @Autowired
+    private FileStorageMutator storageMutator;
+
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+
+    @Autowired
+    private FileUtility fileUtility;
+
+    @Autowired
+    private Misc mistUtility;
+
+    @Autowired
+    private UserServices userService;
+
+    @Value("${files.docservice.url.site}")
+    private String docserviceSite;
+
+    @Value("${files.docservice.url.preloader}")
+    private String docservicePreloader;
+
+    @Value("${url.converter}")
+    private String urlConverter;
+
+    @Value("${url.editor}")
+    private String urlEditor;
+
+    @Value("${files.docservice.languages}")
+    private String langs;
+
+    @Value("${server.version}")
+    private String serverVersion;
+
+    @GetMapping("${url.index}")
+    public String index(@RequestParam(value = "directUrl", required = false) final Boolean directUrl,
+                        final Model model) {
+        java.io.File[] files = storageMutator.getStoredFiles();  // get all the stored files from the storage
+        List<String> docTypes = new ArrayList<>();
+        List<Boolean> filesEditable = new ArrayList<>();
+        List<String> versions = new ArrayList<>();
+        List<Boolean> isFillFormDoc = new ArrayList<>();
+        List<String> langsAndKeys = Arrays.asList(langs.split("\\|"));
+
+        Map<String, String> languages = new LinkedHashMap<>();
+
+        langsAndKeys.forEach((str) -> {
+            String[] couple = str.split(":");
+            languages.put(couple[0], couple[1]);
+        });
+
+        List<User> users = userService.findAll();  // get a list of all the users
+
+        String tooltip = users.stream()  // get the tooltip with the user descriptions
+                .map(user -> mistUtility.convertUserDescriptions(user.getName(),
+                        user.getDescriptions()))  // convert user descriptions to the specified format
+                .collect(Collectors.joining());
+
+        for (java.io.File file:files) {  // run through all the files
+            String fileName = file.getName();  // get file name
+            docTypes.add(fileUtility
+                    .getDocumentType(fileName)
+                    .toString()
+                    .toLowerCase());  // add a document type of each file to the list
+            filesEditable.add(fileUtility.getEditedExts()
+                    .contains(fileUtility.getFileExtension(fileName)));  // specify if a file is editable or not
+            versions.add(" [" + storagePathBuilder.
+                    getFileVersion(fileName, true) + "]");  // add a file version to the list
+            isFillFormDoc.add(fileUtility.getFillExts().contains(fileUtility.getFileExtension(fileName)));
+        }
+
+        // add all the parameters to the model
+        model.addAttribute("isFillFormDoc", isFillFormDoc);
+        model.addAttribute("versions", versions);
+        model.addAttribute("files", files);
+        model.addAttribute("docTypes", docTypes);
+        model.addAttribute("filesEditable", filesEditable);
+        model.addAttribute("datadocs", docserviceSite + docservicePreloader);
+        model.addAttribute("tooltip", tooltip);
+        model.addAttribute("users", users);
+        model.addAttribute("languages", languages);
+        model.addAttribute("directUrl", directUrl);
+        model.addAttribute("serverVersion", serverVersion);
+
+        return "index.html";
+    }
+
+    @PostMapping("/config")
+    @ResponseBody
+    public HashMap<String, String> configParameters() {  // get configuration parameters
+        HashMap<String, String> configuration = new HashMap<>();
+
+        configuration.put("FillExtList", String.join(",", fileUtility
+                .getFillExts()));  // put a list of the extensions that can be filled to config
+        configuration.put("ConverExtList", String.join(",", fileUtility
+                .getConvertExts()));  // put a list of the extensions that can be converted to config
+        configuration.put("EditedExtList", String.join(",", fileUtility
+                .getEditedExts()));  // put a list of the extensions that can be edited to config
+        configuration.put("UrlConverter", urlConverter);
+        configuration.put("UrlEditor", urlEditor);
+
+        return configuration;
+    }
+}

+ 32 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Callback.java

@@ -0,0 +1,32 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.callbacks;
+
+import com.onlyoffice.integration.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
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/CallbackHandler.java

@@ -0,0 +1,50 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.callbacks;
+
+import com.onlyoffice.integration.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(final int code, final Callback callback) {  // register a callback handler
+        callbackHandlers.put(code, callback);
+    }
+
+    public int handle(final Track body, final 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
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/Status.java

@@ -0,0 +1,35 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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(final int codeParam) {
+        this.code = codeParam;
+    }
+    public int getCode() {  // get document status
+        return this.code;
+    }
+}

+ 59 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/EditCallback.java

@@ -0,0 +1,59 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.callbacks.implementations;
+
+import com.onlyoffice.integration.documentserver.callbacks.Callback;
+import com.onlyoffice.integration.documentserver.callbacks.Status;
+import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
+import com.onlyoffice.integration.dto.Action;
+import com.onlyoffice.integration.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(final Track body,
+                      final 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.onlyoffice.integration.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 {
+                    // create a command request to forcibly save the document being edited without closing it
+                    callbackManager.commandRequest("forcesave", key, null);
+                } 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
+    }
+}

+ 50 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/ForcesaveCallback.java

@@ -0,0 +1,50 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.callbacks.implementations;
+
+import com.onlyoffice.integration.documentserver.callbacks.Callback;
+import com.onlyoffice.integration.documentserver.callbacks.Status;
+import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
+import com.onlyoffice.integration.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(final Track body,
+                      final 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 6 - document is being edited, but the current document state is saved
+        return Status.MUST_FORCE_SAVE.getCode();
+    }
+}

+ 50 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/callbacks/implementations/SaveCallback.java

@@ -0,0 +1,50 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.callbacks.implementations;
+
+import com.onlyoffice.integration.documentserver.callbacks.Callback;
+import com.onlyoffice.integration.documentserver.callbacks.Status;
+import com.onlyoffice.integration.documentserver.managers.callback.CallbackManager;
+import com.onlyoffice.integration.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(final Track body,
+                      final 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
+    }
+}

+ 29 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/CallbackManager.java

@@ -0,0 +1,29 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.callback;
+
+import com.onlyoffice.integration.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
+}

+ 352 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/callback/DefaultCallbackManager.java

@@ -0,0 +1,352 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.callback;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
+import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
+import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
+import com.onlyoffice.integration.dto.Action;
+import com.onlyoffice.integration.dto.Track;
+import lombok.SneakyThrows;
+import org.apache.commons.io.IOUtils;
+import org.json.simple.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Primary;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+import java.io.ByteArrayInputStream;
+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.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.onlyoffice.integration.documentserver.util.Constants.FILE_SAVE_TIMEOUT;
+
+// 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;
+
+    // download file from url
+    @SneakyThrows
+    private byte[] getDownloadFile(final String url) {
+        if (url == null || url.isEmpty()) {
+            throw new RuntimeException("Url argument is not specified");  // URL isn't specified
+        }
+
+        URL uri = new URL(url);
+        java.net.HttpURLConnection connection = (java.net.HttpURLConnection) uri.openConnection();
+        connection.setConnectTimeout(FILE_SAVE_TIMEOUT);
+        InputStream stream = connection.getInputStream();  // get input stream of the file information from the URL
+
+        int statusCode = connection.getResponseCode();
+        if (statusCode != HttpStatus.OK.value()) {  // checking status code
+            connection.disconnect();
+            throw new RuntimeException("Document editing service returned status: " + statusCode);
+        }
+
+        if (stream == null) {
+            connection.disconnect();
+            throw new RuntimeException("Input stream is null");
+        }
+
+        return IOUtils.toByteArray(stream);
+    }
+
+    // file saving
+    @SneakyThrows
+    private void saveFile(final byte[] byteArray, final Path path) {
+        if (path == null) {
+            throw new RuntimeException("Path argument is not specified");  // file isn't specified
+        }
+        // update a file or create a new one
+        storageMutator.createOrUpdateFile(path, new ByteArrayInputStream(byteArray));
+    }
+
+    @SneakyThrows
+    public void processSave(final Track body, final 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: Refactoring
+        // convert downloaded file to the file with the current extension if these extensions aren't equal
+        if (!curExt.equals(downloadExt)) {
+            try {
+                String newFileUri = serviceConverter
+                        .getConvertedData(downloadUri, downloadExt, curExt,
+                                serviceConverter.generateRevisionId(downloadUri), null, false,
+                                null).getUri();  // 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);
+            }
+        }
+
+        byte[] byteArrayFile = getDownloadFile(downloadUri);  // download document file
+
+        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
+
+            lastVersion.toFile().renameTo(new File(versionDir + File.separator + "prev." + curExt));
+
+            saveFile(byteArrayFile, toSave); // save document file
+
+            byte[] byteArrayChanges = getDownloadFile(changesUri); // download file changes
+            saveFile(byteArrayChanges, FileSystems.getDefault().getPath(
+                    versionDir + File.separator + "diff.zip")); // 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);
+
+            if (history == null && body.getHistory() != null) {
+                history = objectMapper.writeValueAsString(body.getHistory());
+            }
+
+            if (history != null && !history.isEmpty()) {
+                // write the history changes to the changes.json file
+                storageMutator.writeToFile(versionDir + File.separator + "changes.json", history);
+            }
+
+            // write the key value to the key.txt file
+            storageMutator.writeToFile(versionDir + File.separator + "key.txt", key);
+
+            // get the path to the forcesaved file version and remove it
+            storageMutator.deleteFile(storagePathBuilder.getForcesavePath(newFileName, false));
+        }
+    }
+
+    // todo: Replace (String method) with (Enum method)
+    @SneakyThrows
+    public void commandRequest(final String method,
+                               final String key,
+                               final 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;
+        // check if a secret key to generate token exists or not
+        if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) {
+            Map<String, Object> payloadMap = new HashMap<>();
+            payloadMap.put("payload", params);
+            headerToken = jwtManager.createToken(payloadMap);  // encode a payload object into a header token
+
+            // add a header Authorization with a header token and Authorization prefix in it
+            connection.setRequestProperty(documentJwtHeader.equals("")
+                    ? "Authorization" : documentJwtHeader, "Bearer " + headerToken);
+
+            String token = jwtManager.createToken(params);  // encode a payload object into a body token
+            params.put("token", token);
+        }
+
+        String bodyString = objectMapper.writeValueAsString(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 = serviceConverter.convertStringToJSON(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(final Track body, final String fileNameParam) {  // file force saving process
+
+        String downloadUri = body.getUrl();
+        String fileName = fileNameParam;
+
+        String curExt = fileUtility.getFileExtension(fileName);  // get current file extension
+        String downloadExt = body.getFiletype();  // get an extension of the downloaded file
+
+        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 {
+                // convert file and get URL to a new file
+                String newFileUri = serviceConverter
+                        .getConvertedData(downloadUri, downloadExt, curExt, serviceConverter
+                                .generateRevisionId(downloadUri), null, false, null).getUri();
+                if (newFileUri.isEmpty()) {
+                    newFileName = true;
+                } else {
+                    downloadUri = newFileUri;
+                }
+            } catch (Exception e) {
+                newFileName = true;
+            }
+        }
+
+        byte[] byteArrayFile = getDownloadFile(downloadUri);  // download document file
+        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) {
+                // get the correct file name if it already exists
+                fileName = documentManager
+                        .getCorrectName(fileUtility
+                                .getFileNameWithoutExtension(fileName) + "-form." + downloadExt);
+            } 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
+            // create meta data for the forcesaved file
+            storageMutator.createMeta(fileName, user, "Filling Form");
+
+            try {
+                String formsDataUrl = body.getFormsdataurl();
+
+                if (formsDataUrl != null && !formsDataUrl.isEmpty()) {
+                    String formsName = documentManager.getCorrectName(fileUtility
+                            .getFileNameWithoutExtension(fileName) + ".txt");
+                    String formsPath = storagePathBuilder.getFileLocation(formsName);
+
+                    byte[] byteArrayFormsData = getDownloadFile(formsDataUrl);
+
+                    saveFile(byteArrayFormsData, Paths.get(formsPath));
+                } else {
+                    throw new RuntimeException("Document editing service did not return formsDataUrl");
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else {
+            if (newFileName) {
+                fileName = documentManager
+                        .getCorrectName(fileUtility.getFileNameWithoutExtension(fileName) + downloadExt);
+            }
+
+            forcesavePath = storagePathBuilder.getForcesavePath(fileName, false);
+            if (forcesavePath.isEmpty()) {
+                forcesavePath = storagePathBuilder.getForcesavePath(fileName, true);
+            }
+        }
+
+        saveFile(byteArrayFile, FileSystems.getDefault().getPath(forcesavePath));
+    }
+}

+ 247 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DefaultDocumentManager.java

@@ -0,0 +1,247 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.document;
+
+import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
+import 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.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.FileSystems;
+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;
+
+import static com.onlyoffice.integration.documentserver.util.Constants.KILOBYTE_SIZE;
+
+@Component
+@Primary
+public class DefaultDocumentManager implements DocumentManager {
+
+    @Value("${files.storage.folder}")
+    private String storageFolder;
+    @Value("${files.storage}")
+    private String filesStorage;
+    @Value("${url.track}")
+    private String trackUrl;
+    @Value("${url.download}")
+    private String downloadUrl;
+
+    @Autowired
+    private FileStorageMutator storageMutator;
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+    @Autowired
+    private FileUtility fileUtility;
+    @Autowired
+    private ServiceConverter serviceConverter;
+
+    // get URL to the created file
+    public String getCreateUrl(final String fileName, final Boolean sample) {
+        String fileExt = fileUtility.getFileExtension(fileName);
+        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(final 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));
+
+        // run through all the files with such a name in the storage directory
+        for (int i = 1; Files.exists(path); i++) {
+            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(final String fileName, final 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(final String fileName, final Integer version, final String file,
+                                    final 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(final String fileName) {
+        String serverPath = storagePathBuilder.getServerUrl(true);
+        String storageAddress = storagePathBuilder.getStorageLocation();
+        try {
+            String query = trackUrl + "?fileName="
+                    + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString())
+                    + "&userAddress=" + URLEncoder
+                    .encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString());
+            return serverPath + query;
+        } catch (UnsupportedEncodingException e) {
+            return "";
+        }
+    }
+
+    // get URL to download a file
+    public String getDownloadUrl(final String fileName, final Boolean isServer) {
+        String serverPath = storagePathBuilder.getServerUrl(isServer);
+        String storageAddress = storagePathBuilder.getStorageLocation();
+        try {
+            String userAddress = isServer ? "&userAddress=" + URLEncoder
+                    .encode(storageAddress, java.nio.charset.StandardCharsets.UTF_8.toString()) : "";
+            String query = downloadUrl + "?fileName="
+                    + URLEncoder.encode(fileName, java.nio.charset.StandardCharsets.UTF_8.toString())
+                    + userAddress;
+
+            return serverPath + query;
+        } catch (UnsupportedEncodingException e) {
+            return "";
+        }
+    }
+
+    // get file information
+    public ArrayList<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() / Double.valueOf(KILOBYTE_SIZE))))
+                    .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(final 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(final String path, final Integer version, final boolean historyPath) {
+        if (!historyPath) {
+            return storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(path)) + version;
+        }
+        return path + File.separator + version;
+    }
+
+    // create demo document
+    public String createDemo(final String fileExt, final Boolean sample, final String uid, final String uname) {
+        String demoName = (sample ? "sample." : "new.")
+                + fileExt;  // create sample or new template file with the necessary extension
+        String demoPath =
+            "assets"
+            + File.separator
+            + "document-templates"
+            + File.separator
+            + (sample ? "sample" : "new")
+            + File.separator
+            + demoName;
+
+        // get a file name with an index if the file with such a name already exists
+        String fileName = getCorrectName(demoName);
+
+        InputStream stream = Thread.currentThread()
+                                    .getContextClassLoader()
+                                    .getResourceAsStream(demoPath);  // get the input file stream
+
+        if (stream == null) {
+            return null;
+        }
+
+        storageMutator.createFile(FileSystems.getDefault().getPath(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;
+    }
+}

+ 42 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/document/DocumentManager.java

@@ -0,0 +1,42 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.document;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+// specify the document manager functions
+public interface DocumentManager {
+
+    // get a file name with an index if the file with such a name already exists
+    String getCorrectName(String fileName);
+    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 fileName);  // 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
+
+    //  get the path to the file version by the history path and file version
+    String versionDir(String path, Integer version, boolean historyPath);
+
+    // create demo document
+    String createDemo(String fileExt, Boolean sample, String uid, String uname) throws Exception;
+    String getCreateUrl(String fileName, Boolean sample);  // get URL to the created file
+}

+ 341 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/history/DefaultHistoryManager.java

@@ -0,0 +1,341 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.history;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
+import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
+import com.onlyoffice.integration.documentserver.models.filemodel.Document;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
+import lombok.SneakyThrows;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.file.Paths;
+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;
+
+    @Autowired
+    private ServiceConverter serviceConverter;
+
+    // todo: Refactoring
+    @SneakyThrows
+    public String[] getHistory(final Document document) {  // get document history
+
+        // get history directory
+        String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(document.getTitle()));
+        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 = (JSONObject) parser.parse(createdInfo);  // and turn it into json object
+
+                    // write meta information to the object (user information and creation date)
+                    obj.put("created", json.get("created"));
+                    Map<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()));
+                dataObj.put("key", key);
+                dataObj.put("url", i == curVer ? document.getUrl()
+                        : documentManager.getHistoryFileUrl(document.getTitle(), i, "prev." + fileUtility
+                        .getFileExtension(document.getTitle()), true));
+                if (!document.getDirectUrl().equals("")) {
+                    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 = (JSONObject) parser.parse(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"));
+
+                    // get the history data from the previous file version
+                    Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(i - 2));
+                    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"));
+                    if (!document.getDirectUrl().equals("")) {
+                        prevInfo.put("directUrl", prev.get("directUrl"));
+                    }
+
+                    // write information about previous file version to the data object
+                    dataObj.put("previous", prevInfo);
+                    // 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[]{"", ""};
+    }
+
+    // todo: Refactoring
+    @SneakyThrows
+    public String getHistory(final String fileName) {  // get document history
+
+        // get history directory
+        String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(fileName));
+        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<>();
+
+            for (Integer i = 1; i <= curVer; i++) {  // run through all the file versions
+                Map<String, Object> obj = new HashMap<String, Object>();
+                String verDir = documentManager
+                        .versionDir(histDir, i, true);  // get the path to the given file version
+
+                String key;
+                if (i == curVer) {
+                    key = serviceConverter
+                            .generateRevisionId(storagePathBuilder.getStorageLocation()
+                                    + "/" + fileName + "/"
+                                    + new File(storagePathBuilder.getFileLocation(fileName)).lastModified());
+                } else {
+                    key = readFileToEnd(new File(verDir + File.separator + "key.txt"));
+                }
+
+                obj.put("key", key);
+                obj.put("version", i);
+
+                if (i == 1) {  // check if the version number is equal to 1
+                    String createdInfo = readFileToEnd(new File(histDir
+                            + File.separator + "createdInfo.json"));  // get file with meta data
+                    JSONObject json = (JSONObject) parser.parse(createdInfo);  // and turn it into json object
+
+                    // write meta information to the object (user information and creation date)
+                    obj.put("created", json.get("created"));
+                    Map<String, Object> user = new HashMap<String, Object>();
+                    user.put("id", json.get("id"));
+                    user.put("name", json.get("name"));
+                    obj.put("user", user);
+                }
+
+                if (i > 1) {  //check if the version number is greater than 1
+                    // if so, get the path to the changes.json file
+                    JSONObject changes = (JSONObject) parser.parse(readFileToEnd(new File(documentManager
+                            .versionDir(histDir, i - 1, 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"));
+                }
+
+                hist.add(obj);
+            }
+
+            // 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 objectMapper.writeValueAsString(histObj);
+            } catch (JsonProcessingException e) {
+                e.printStackTrace();
+            }
+        }
+        return "";
+    }
+
+    // todo: Refactoring
+    @SneakyThrows
+    public String getHistoryData(final String fileName, final String version, final Boolean directUrl) {
+        // get history directory
+        String histDir = storagePathBuilder.getHistoryDir(storagePathBuilder.getFileLocation(fileName));
+        Integer curVer = storagePathBuilder.getFileVersion(histDir, false);  // get current file version
+
+        if (curVer > 0) {  // check if the current file version is greater than 0
+            Map<String, Object> histData = new HashMap<>();
+
+            for (Integer i = 1; i <= curVer; i++) {  // run through all the file versions
+                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;
+                if (i == curVer) {
+                    key = serviceConverter
+                            .generateRevisionId(storagePathBuilder.getStorageLocation()
+                                    + "/" + fileName + "/"
+                                    + new File(storagePathBuilder.getFileLocation(fileName)).lastModified());
+                } else {
+                    key = readFileToEnd(new File(verDir + File.separator + "key.txt"));
+                }
+
+                dataObj.put("fileType", fileUtility
+                        .getFileExtension(fileName).replace(".", ""));
+                dataObj.put("key", key);
+                dataObj.put("url", i == curVer ? documentManager.getDownloadUrl(fileName, true)
+                        : documentManager.getHistoryFileUrl(fileName, i, "prev" + fileUtility
+                        .getFileExtension(fileName), true));
+                if (directUrl) {
+                    dataObj.put("directUrl", i == curVer
+                            ? documentManager.getDownloadUrl(fileName, false)
+                            : documentManager.getHistoryFileUrl(fileName, i, "prev" + fileUtility
+                                    .getFileExtension(fileName), false));
+                }
+                dataObj.put("version", i);
+
+                if (i > 1) {  //check if the version number is greater than 1
+                    Integer verdiff = i - 1;
+                    // get the history data from the previous file version
+                    Map<String, Object> prev = (Map<String, Object>) histData.get(Integer.toString(verdiff));
+                    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"));
+                    if (directUrl) {
+                        prevInfo.put("directUrl", prev.get("directUrl"));
+                    }
+
+                    // write information about previous file version to the data object
+                    dataObj.put("previous", prevInfo);
+
+                    if (diffExists(histDir, verdiff)) {
+                        // write the path to the diff.zip archive with differences in this file version
+                        dataObj.put("changesUrl", documentManager
+                                .getHistoryFileUrl(fileName, verdiff, "diff.zip", true));
+                    }
+                }
+
+                if (jwtManager.tokenEnabled()) {
+                    dataObj.put("token", jwtManager.createToken(dataObj));
+                }
+
+                histData.put(Integer.toString(i), dataObj);
+            }
+
+            try {
+                return objectMapper.writeValueAsString(histData.get(version));
+            } catch (JsonProcessingException e) {
+                e.printStackTrace();
+            }
+        }
+        return "";
+    }
+
+
+    // read a file
+    private String readFileToEnd(final File file) {
+        String output = "";
+        try {
+            try (FileInputStream is = new FileInputStream(file)) {
+                Scanner scanner = new Scanner(is);  // read data from the source
+                scanner.useDelimiter("\\A");
+                while (scanner.hasNext()) {
+                    output += scanner.next();
+                }
+                scanner.close();
+            }
+        } catch (Exception e) {
+        }
+        return output;
+    }
+
+    // diff.zip existence check
+    private Boolean diffExists(final String histDir, final Integer verdiff) {
+        String filePath = Paths.get(histDir, String.valueOf(verdiff), "diff.zip").toString();
+        File file = new File(filePath);
+        return file.exists();
+    }
+}

+ 26 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/history/HistoryManager.java

@@ -0,0 +1,26 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.history;
+
+// specify the history manager functions
+public interface HistoryManager {
+    String getHistory(String fileName);  // get document history
+
+    String getHistoryData(String fileName, String version, Boolean directUrl); // get document history data
+}

+ 131 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/DefaultJwtManager.java

@@ -0,0 +1,131 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.jwt;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang3.StringUtils;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+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;
+    @Value("${files.docservice.token-use-for-request}")
+    private String tokenUseForRequest;
+    @Autowired
+    private ObjectMapper objectMapper;
+    @Autowired
+    private JSONParser parser;
+
+    // create document token
+    public String createToken(final 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();
+    }
+
+    public boolean tokenUseForRequest() {
+        return Boolean.parseBoolean(tokenUseForRequest) && !tokenUseForRequest.isEmpty();
+    }
+
+    // read document token
+    public JWT readToken(final String token) {
+        try {
+            // build a HMAC verifier using the token secret
+            Verifier verifier = HMACVerifier.newVerifier(tokenSecret);
+
+            // verify and decode the encoded string JWT to a rich object
+            return JWT.getDecoder().decode(token, verifier);
+        } catch (Exception exception) {
+            return null;
+        }
+    }
+
+    // parse the body
+    public JSONObject parseBody(final String payload, final String header) {
+        JSONObject body;
+        try {
+            Object obj = parser.parse(payload);  // get body parameters by parsing the payload
+            body = (JSONObject) obj;
+        } catch (Exception ex) {
+            throw new RuntimeException("{\"error\":1,\"message\":\"JSON Parsing error\"}");
+        }
+        if (tokenEnabled() && tokenUseForRequest()) {  // 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
+
+                    // get token from the header (it is placed after the Bearer prefix if it exists)
+                    token = header.startsWith("Bearer ") ? header.substring("Bearer ".length()) : header;
+                }
+            }
+            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\"}");
+            }
+            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");
+
+                    jwt.claims = jwtPayload;
+                } catch (Exception ex) {
+                    throw new RuntimeException("{\"error\":1,\"message\":\"Wrong payload\"}");
+                }
+            }
+            try {
+                Object obj = parser.parse(objectMapper.writeValueAsString(jwt.claims));
+                body = (JSONObject) obj;
+            } catch (Exception ex) {
+                throw new RuntimeException("{\"error\":1,\"message\":\"Parsing error\"}");
+            }
+        }
+
+        return body;
+    }
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/jwt/JwtManager.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.jwt;
+
+import org.json.simple.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
+    boolean tokenUseForRequest();  // 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
+}

+ 70 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/template/SampleTemplateManager.java

@@ -0,0 +1,70 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.template;
+
+import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
+import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
+import com.onlyoffice.integration.documentserver.models.filemodel.Template;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.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(final String fileName) {
+        List<Template> templates = new ArrayList<>();
+        templates.add(new Template("", "Blank", documentManager
+                        .getCreateUrl(fileName, false)));  // create a blank template
+        templates.add( new Template(getTemplateImageUrl(fileName), "With sample content", documentManager
+                        .getCreateUrl(fileName,
+                                true)));  // create a template with sample content using the template image
+
+        return templates;
+    }
+
+    // get the template image URL for the specified file
+    public String getTemplateImageUrl(final 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)
+    }
+}

+ 29 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/managers/template/TemplateManager.java

@@ -0,0 +1,29 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.managers.template;
+
+import com.onlyoffice.integration.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
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/AbstractModel.java

@@ -0,0 +1,24 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models;
+
+import java.io.Serializable;
+
+public abstract class AbstractModel implements Serializable {
+}

+ 36 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/Format.java

@@ -0,0 +1,36 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models;
+
+import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.util.List;
+
+@Getter
+@Setter
+@ToString
+public class Format {
+    private String name;
+    private DocumentType type;
+    private List<String> actions;
+    private List<String> convert;
+    private List<String> mime;
+}

+ 52 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Customization.java

@@ -0,0 +1,52 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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
+/* 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. */
+public class Customization {
+    @Autowired
+    private Goback goback;  // the settings for the Open file location menu button and upper right corner button
+    private Boolean autosave = true;  // 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 = true;  // if the Submit form button is displayed or hidden
+    private Boolean about = true;
+    private Boolean plugins = true;
+    private Boolean feedback = true;
+}

+ 40 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Embedded.java

@@ -0,0 +1,40 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.configurations;
+
+import com.onlyoffice.integration.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
+/* The parameters which allow to change the settings
+ which define the behavior of the buttons in the embedded mode */
+public class Embedded {
+    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
+}

+ 48 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Goback.java

@@ -0,0 +1,48 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.configurations;
+
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import lombok.Getter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+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;
+
+    @Value("${url.index}")
+    private String indexMapping;
+
+    @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) + indexMapping;
+    }
+}

+ 45 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Info.java

@@ -0,0 +1,45 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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
+/* The additional parameters for the document (document owner, folder where the document is stored,
+ uploading date, sharing settings) */
+public class Info {
+    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());
+    }
+}

+ 18 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/configurations/Plugins.java

@@ -0,0 +1,18 @@
+package com.onlyoffice.integration.documentserver.models.configurations;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Scope("prototype")
+@Getter
+@Setter
+public class Plugins {
+    private List<String> autostart = new ArrayList<>();
+    private List<String> pluginsData = new ArrayList<>();
+}

+ 32 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Action.java

@@ -0,0 +1,32 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.enums;
+
+public enum Action {
+    edit,
+    review,
+    view,
+    embedded,
+    filter,
+    comment,
+    chat,
+    fillForms,
+    blockcontent,
+    protect
+}

+ 48 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/ConvertErrorType.java

@@ -0,0 +1,48 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.enums;
+
+public enum ConvertErrorType {
+    EMPTY_ERROR(0, ""),
+    CONVERTATION_UNKNOWN(-1, "Error convertation unknown"),
+    CONVERTATION_TIMEOUT(-2, "Error convertation timeout"),
+    CONVERTATION_ERROR(-3, "Error convertation error"),
+    DOWNLOAD_ERROR(-4, "Error download error"),
+    UNEXPECTED_GUID_ERROR(-5, "Error unexpected guid"),
+    DATABASE_ERROR(-6, "Error database"),
+    DOCUMENT_REQUEST_ERROR(-7, "Error document request"),
+    DOCUMENT_VKEY_ERROR(-8, "Error document VKey");
+
+    private final int code;
+    private final String label;
+
+    ConvertErrorType(final int codeParam, final String labelParam) {
+        this.code = codeParam;
+        this.label = labelParam;
+    }
+
+    public static String labelOfCode(final int code) {
+        for (ConvertErrorType convertErrorType : values()) {
+            if (convertErrorType.code == code) {
+                return convertErrorType.label;
+            }
+        }
+        return "ErrorCode = " + code;
+    }
+}

+ 25 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/DocumentType.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.enums;
+
+public enum DocumentType {
+    word,
+    cell,
+    slide
+}

+ 24 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Mode.java

@@ -0,0 +1,24 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.enums;
+
+public enum Mode {
+    edit,
+    view
+}

+ 24 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/ToolbarDocked.java

@@ -0,0 +1,24 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.enums;
+
+public enum ToolbarDocked {
+    top,
+    bottom
+}

+ 25 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/enums/Type.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.enums;
+
+public enum Type {
+    desktop,
+    mobile,
+    embedded
+}

+ 41 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/CommentGroup.java

@@ -0,0 +1,41 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.filemodel;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.onlyoffice.integration.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
+}

+ 49 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Document.java

@@ -0,0 +1,49 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.filemodel;
+
+import com.onlyoffice.integration.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;
+
+import java.util.HashMap;
+
+@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 urlUser;  /* the absolute URL that will allow the document to be saved
+    onto the user personal computer */
+    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
+    private String directUrl;
+    private HashMap<String, Object> referenceData;
+}

+ 61 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/EditorConfig.java

@@ -0,0 +1,61 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.filemodel;
+
+import com.onlyoffice.integration.documentserver.models.configurations.Customization;
+import com.onlyoffice.integration.documentserver.models.configurations.Embedded;
+import com.onlyoffice.integration.documentserver.models.configurations.Plugins;
+import com.onlyoffice.integration.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 */
+    private Plugins plugins = new Plugins();
+}

+ 44 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/FileModel.java

@@ -0,0 +1,44 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.filemodel;
+
+import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
+import com.onlyoffice.integration.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
+/* the file base parameters which include the platform type used,
+ document display size (width and height) and type of the document opened */
+public class FileModel {
+    @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
+}

+ 55 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Permission.java

@@ -0,0 +1,55 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.filemodel;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.onlyoffice.integration.documentserver.models.AbstractModel;
+import com.onlyoffice.integration.documentserver.serializers.SerializerFilter;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@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
+    @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
+    private List<String> reviewGroups;  // the groups whose changes the user can accept/reject
+    @Autowired
+    private CommentGroup commentGroups;  //  the groups whose comments the user can edit, remove and/or view
+    @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = SerializerFilter.class)
+    private List<String> userInfoGroups;
+    private Boolean protect = true;
+}

+ 43 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/ReferenceData.java

@@ -0,0 +1,43 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.filemodel;
+
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ReferenceData {
+    @Autowired
+    private FileStoragePathBuilder storagePathBuilder;
+    private final String instanceId;
+    private final Map<String, String> fileKey;
+    public ReferenceData(final String fileName, final String curUserHostAddress, final User user) {
+        instanceId = storagePathBuilder.getServerUrl(true);
+        Map<String, String> fileKeyList = new HashMap<>();
+        if (!user.getId().equals("uid-0")) {
+            fileKeyList.put("fileName", fileName);
+            fileKeyList.put("userAddress", curUserHostAddress);
+        } else {
+            fileKeyList = null;
+        }
+        fileKey = fileKeyList;
+    }
+}

+ 32 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/Template.java

@@ -0,0 +1,32 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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
+}

+ 46 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/models/filemodel/User.java

@@ -0,0 +1,46 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.models.filemodel;
+
+import com.onlyoffice.integration.documentserver.models.AbstractModel;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+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 FileStoragePathBuilder storagePathBuilder;
+    private String id;
+    private String name;
+    private String group;
+    private String image;
+
+    // the user configuration parameters
+    public void configure(final int idParam, final String nameParam, final String groupParam) {
+        this.id = "uid-" + idParam;  // the user id
+        this.name = nameParam;  // the user name
+        this.group = groupParam;  // the group the user belongs to
+        this.image = storagePathBuilder.getServerUrl(true) + "/css/img/uid-" + this.id + ".png";
+    }
+}

+ 23 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/serializers/FilterState.java

@@ -0,0 +1,23 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.serializers;
+
+public enum FilterState {
+    NULL
+}

+ 38 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/serializers/SerializerFilter.java

@@ -0,0 +1,38 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.serializers;
+
+import java.util.List;
+
+public class SerializerFilter {
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj instanceof List) {
+            if (((List<?>) obj).size() == 1 && ((List<?>) obj).get(0) == FilterState.NULL.toString()) {
+                return true;
+            }
+            return false;
+        }
+        return false;
+    }
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+}

+ 43 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/storage/FileStorageMutator.java

@@ -0,0 +1,43 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.storage;
+
+import org.springframework.core.io.Resource;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+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) throws UnsupportedEncodingException;  // delete a file
+    boolean deleteFileHistory(String fileName) throws UnsupportedEncodingException;  // 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, ByteArrayInputStream stream);  // create or update a file
+}

+ 31 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/storage/FileStoragePathBuilder.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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 */
+}

+ 388 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/storage/LocalFileStorage.java

@@ -0,0 +1,388 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.storage;
+
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import lombok.Getter;
+import lombok.SneakyThrows;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.json.simple.JSONObject;
+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;
+
+import static com.onlyoffice.integration.documentserver.util.Constants.KILOBYTE_SIZE;
+
+// 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;
+
+    @Autowired
+    private HttpServletRequest request;
+
+    /*
+        This Storage configuration method should be called whenever a new storage folder is required
+     */
+    public void configure(final 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(final 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(final 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(final Path path, final 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[KILOBYTE_SIZE];
+                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(final String fileNameParam) throws UnsupportedEncodingException {
+        String fileName = URLDecoder
+                .decode(fileNameParam, StandardCharsets.UTF_8.name());  // decode a x-www-form-urlencoded string
+        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
+
+        // delete the specified file; for directories, recursively delete any nested directories or files as well
+        boolean fileDeleted = FileSystemUtils.deleteRecursively(filePath.toFile());
+        /* delete the specified file without extension; for directories,
+         recursively delete any nested directories or files as well */
+        boolean fileWithoutExtDeleted = FileSystemUtils.deleteRecursively(filePathWithoutExt.toFile());
+
+        return fileDeleted && fileWithoutExtDeleted;
+    }
+
+    // delete file history
+    public boolean deleteFileHistory(final String fileNameParam) throws UnsupportedEncodingException {
+        String fileName = URLDecoder
+                .decode(fileNameParam, StandardCharsets.UTF_8.name());  // decode a x-www-form-urlencoded string
+        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
+
+        /* delete the specified history file; for directories,
+         recursively delete any nested directories or files as well */
+        boolean historyDeleted = FileSystemUtils.deleteRecursively(fileHistoryPath.toFile());
+
+        /* delete the specified history file without extension; for directories,
+         recursively delete any nested directories or files as well */
+        boolean historyWithoutExtDeleted = FileSystemUtils.deleteRecursively(fileHistoryPathWithoutExt.toFile());
+
+        return historyDeleted || historyWithoutExtDeleted;
+    }
+
+    // update a file
+    public String updateFile(final String fileName, final 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(final Path source, final 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(final String pathName, final 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(final String fileName, final 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(final 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(final String fileName, final String version, final 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(final String fileName,
+                           final String uid,
+                           final 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)) {
+            json.writeJSONString(writer);
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    // create or update a file
+    public boolean createOrUpdateFile(final Path path, final ByteArrayInputStream 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, IOUtils.toByteArray(stream));  // 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(final Boolean forDocumentServer) {
+        if (forDocumentServer && !docserviceUrlExample.equals("")) {
+            return docserviceUrlExample;
+        } else {
+            return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+                    + request.getContextPath();
+        }
+    }
+
+    // get the history directory
+    public String getHistoryDir(final String path) {
+        return path + historyPostfix;
+    }
+
+    // get the file version
+    public int getFileVersion(final String historyPath, final 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
+        }
+        }
+
+        // run through all the files in the history directory
+        try (Stream<Path> stream = Files.walk(path, 1)) {
+            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;
+        }
+    }
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/Constants.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util;
+
+public final class Constants {
+    public static final Integer MAX_FILE_SIZE = 5 * 1024 * 1024;
+    public static final Integer CONVERT_TIMEOUT_MS = 120000;
+    public static final String CONVERTATION_ERROR_MESSAGE_TEMPLATE = "Error occurred in the ConvertService: ";
+    public static final Long FULL_LOADING_IN_PERCENT = 100L;
+    public static final Integer FILE_SAVE_TIMEOUT = 5000;
+    public static final Integer MAX_KEY_LENGTH = 20;
+    public static final Integer ANONYMOUS_USER_ID = 4;
+    public static final Integer KILOBYTE_SIZE = 1024;
+
+    private Constants() { }
+}
+

+ 36 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/Misc.java

@@ -0,0 +1,36 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util;
+
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Component
+public class Misc {
+
+    // convert user descriptions to the specified format
+    public String convertUserDescriptions(final String username, final List<String> description) {
+        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;
+    }
+}

+ 72 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/SSLUtils.java

@@ -0,0 +1,72 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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(final String hostname, final SSLSession sslSession) {
+            return true;
+        }
+    };
+
+    private final TrustManager[] unquestioningTrustManager = new TrustManager[] {
+            new X509TrustManager() {
+        public X509Certificate[] getAcceptedIssuers() {
+            return null;
+        }
+
+        public void checkClientTrusted(final X509Certificate[] certs, final String authType) {
+        }
+
+        public void checkServerTrusted(final X509Certificate[] certs, final 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, unquestioningTrustManager, 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());
+    }
+
+}

+ 167 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/file/DefaultFileUtility.java

@@ -0,0 +1,167 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util.file;
+
+import com.onlyoffice.integration.documentserver.models.Format;
+import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
+import com.onlyoffice.integration.documentserver.util.service.FormatService;
+import org.springframework.beans.factory.annotation.Autowired;
+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.List;
+
+import static com.onlyoffice.integration.documentserver.util.Constants.MAX_FILE_SIZE;
+
+@Component
+@Qualifier("default")
+public class DefaultFileUtility implements FileUtility {
+    @Value("${filesize-max}")
+    private String filesizeMax;
+    @Value("${filename-max}")
+    private String filenameMax;
+
+    @Autowired
+    private FormatService formatService;
+
+    // get the document type
+    public DocumentType getDocumentType(final String fileName) {
+        String ext = getFileExtension(fileName).toLowerCase();  // get file extension from its name
+
+        List<Format> formats = formatService.getFormats();
+        for (Format format : formats) {
+            if (format.getName().equals(ext)) {
+                return format.getType();
+            }
+        }
+
+        // default file type is word
+        return DocumentType.word;
+    }
+
+    // get file name from its URL
+    public String getFileName(final 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(final 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(final String url) {
+        String fileName = getFileName(url);
+        if (fileName == null) {
+            return null;
+        }
+        String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1);
+        return fileExt.toLowerCase();
+    }
+
+    // get an editor internal extension
+    public String getInternalExtension(final 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 formatService.fillableExtensions();
+    }
+
+    // get file extensions that can be viewed
+    public List<String> getViewedExts() {
+        return formatService.viewableExtensions();
+    }
+
+    // get file extensions that can be edited
+    public List<String> getEditedExts() {
+        return formatService.editableExtensions();
+    }
+
+    // get file extensions that can be converted
+    public List<String> getConvertExts() {
+        return formatService.autoConvertExtensions();
+    }
+
+    // get all the supported file extensions
+    public List<String> getFileExts() {
+        return formatService.allExtensions();
+    }
+
+    // generate the file path from file directory and name
+    public Path generateFilepath(final String directory, final String fullFileName) {
+        int maxName = Integer.parseInt(filenameMax);
+        String fileName = getFileNameWithoutExtension(fullFileName);
+        if (fileName.length() > maxName) {
+            fileName = fileName.substring(0, maxName) + "[...]";
+        }
+        String fileExtension = getFileExtension(fullFileName);  // get file extension
+        // get the path to the files with the specified name
+        Path path = Paths.get(directory + fileName + "." + fileExtension);
+
+        for (int i = 1; Files.exists(path); i++) {  // run through all the files with the specified name
+            // get a name of each file without extension and add an index to it
+            fileName = fileName + "(" + i + ")";
+
+            // create a new path for this file with the correct name and extension
+            path = Paths.get(directory + fileName + "." + fileExtension);
+        }
+
+        path = Paths.get(directory + fileName + "." + fileExtension);
+        return path;
+    }
+
+    // get maximum file size
+    public long getMaxFileSize() {
+        long size = Long.parseLong(filesizeMax);
+        return size > 0 ? size : MAX_FILE_SIZE;
+    }
+}

+ 41 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/file/FileUtility.java

@@ -0,0 +1,41 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util.file;
+
+import com.onlyoffice.integration.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
+}

+ 103 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/DefaultFormatService.java

@@ -0,0 +1,103 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util.service;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.onlyoffice.integration.documentserver.models.Format;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Service
+public class DefaultFormatService implements FormatService {
+    private List<Format> formats;
+    @Autowired
+    public DefaultFormatService(
+            @Value("classpath:assets/document-formats/onlyoffice-docs-formats.json") final Resource resourceFile,
+            final ObjectMapper objectMapper
+    ) {
+        try {
+            objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
+            File targetFile = resourceFile.getFile();
+            this.formats = objectMapper.readValue(targetFile, new TypeReference<List<Format>>() { });
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public List<Format> getFormats() {
+        return this.formats;
+    }
+
+    public List<Format> getFormatsByAction(final String action) {
+        return this
+                .formats
+                .stream()
+                .filter(format -> format.getActions().contains(action))
+                .collect(Collectors.toList());
+    }
+
+    public List<String> allExtensions() {
+        return this
+                .formats
+                .stream()
+                .map(format -> format.getName())
+                .collect(Collectors.toList());
+    }
+
+    public List<String> fillableExtensions() {
+        return this
+                .getFormatsByAction("fill")
+                .stream()
+                .map(format -> format.getName())
+                .collect(Collectors.toList());
+    }
+
+    public List<String> viewableExtensions() {
+        return this
+                .getFormatsByAction("view")
+                .stream()
+                .map(format -> format.getName())
+                .collect(Collectors.toList());
+    }
+
+    public List<String> editableExtensions() {
+        return Stream
+                .of(this.getFormatsByAction("edit"), this.getFormatsByAction("lossy-edit"))
+                .flatMap(x -> x.stream())
+                .map(format -> format.getName())
+                .collect(Collectors.toList());
+    }
+
+    public List<String> autoConvertExtensions() {
+        return this
+                .getFormatsByAction("auto-convert")
+                .stream()
+                .map(format -> format.getName())
+                .collect(Collectors.toList());
+    }
+}

+ 265 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/DefaultServiceConverter.java

@@ -0,0 +1,265 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
+import com.onlyoffice.integration.documentserver.models.enums.ConvertErrorType;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.dto.Convert;
+import com.onlyoffice.integration.dto.ConvertedData;
+import lombok.SneakyThrows;
+import org.apache.commons.lang3.StringUtils;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+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;
+
+import static com.onlyoffice.integration.documentserver.util.Constants.*;
+
+// 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;
+
+    @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
+        convertTimeout = timeout > 0 ? timeout : CONVERT_TIMEOUT_MS;
+    }
+
+    @SneakyThrows
+    private String postToServer(final Convert body, final 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
+            }
+
+            int statusCode = connection.getResponseCode();
+            if (statusCode != HttpStatus.OK.value()) {  // checking status code
+                connection.disconnect();
+                throw new RuntimeException("Convertation service returned status: " + statusCode);
+            }
+
+            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 ConvertedData getConvertedData(final String documentUri, final String fromExtension,
+                                          final String toExtension, final String documentRevisionId,
+                                          final String filePass, final Boolean isAsync, final String lang) {
+        // check if the fromExtension parameter is defined; if not, get it from the document url
+        String fromExt = 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;
+
+        String documentRevId = documentRevisionId == null || documentRevisionId.isEmpty()
+                ? documentUri : documentRevisionId;
+
+        documentRevId = generateRevisionId(documentRevId);  // 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);
+        body.setFiletype(fromExt);
+        body.setTitle(title);
+        body.setKey(documentRevId);
+        body.setFilePass(filePass);
+        if (isAsync) {
+            body.setAsync(true);
+        }
+
+        String headerToken = "";
+        if (jwtManager.tokenEnabled() && jwtManager.tokenUseForRequest()) {
+            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 getResponseData(jsonString);
+    }
+
+    // generate document key
+    public String generateRevisionId(final String expectedKey) {
+        /* if the expected key length is greater than 20
+        then he expected key is hashed and a fixed length value is stored in the string format */
+        String formatKey = expectedKey.length() > MAX_KEY_LENGTH
+                ? Integer.toString(expectedKey.hashCode()) : expectedKey;
+        String key = formatKey.replace("[^0-9-.a-zA-Z_=]", "_");
+
+        return key.substring(0, Math.min(key.length(), MAX_KEY_LENGTH));  // the resulting key length is 20 or less
+    }
+
+    // todo: Replace with a registry (callbacks package for reference)
+    // create an error message for an error code
+    private void processConvertServiceResponceError(final int errorCode) {
+        String errorMessage = CONVERTATION_ERROR_MESSAGE_TEMPLATE + ConvertErrorType.labelOfCode(errorCode);
+
+        throw new RuntimeException(errorMessage);
+    }
+
+    // get the response URL
+    @SneakyThrows
+    private ConvertedData getResponseData(final String jsonString) {
+        JSONObject jsonObj = convertStringToJSON(jsonString);
+
+        Object error = jsonObj.get("error");
+        if (error != null) {  // if an error occurs
+            processConvertServiceResponceError(Math.toIntExact((long) error));  // then get an error message
+        }
+
+        // check if the conversion is completed and save the result to a variable
+        Boolean isEndConvert = (Boolean) jsonObj.get("endConvert");
+
+        Long resultPercent = 0L;
+        String responseUri = null;
+        String responseFileType = null;
+        ConvertedData convertedData = new ConvertedData("", "");
+
+        if (isEndConvert) {  // if the conversion is completed
+            resultPercent = FULL_LOADING_IN_PERCENT;
+            responseUri = (String) jsonObj.get("fileUrl");  // get the file URL
+            responseFileType = (String) jsonObj.get("fileType");  // get the file type
+            convertedData.setUri(responseUri);
+            convertedData.setFileType(responseFileType);
+        } else {  // if the conversion isn't completed
+            resultPercent = (Long) jsonObj.get("percent");
+
+            // get the percentage value of the conversion process
+            resultPercent = resultPercent >= FULL_LOADING_IN_PERCENT ? FULL_LOADING_IN_PERCENT - 1 : resultPercent;
+        }
+
+        return convertedData;
+    }
+
+    // convert stream to string
+    @SneakyThrows
+    public String convertStreamToString(final InputStream stream) {
+        InputStreamReader inputStreamReader = new InputStreamReader(stream);  // create an object to get incoming stream
+        StringBuilder stringBuilder = new StringBuilder();  // create a string builder object
+
+        // create an object to read incoming streams
+        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+        String line = bufferedReader.readLine();  // get incoming streams by lines
+
+        while (line != null) {
+            stringBuilder.append(line);  // concatenate strings using the string builder
+            line = bufferedReader.readLine();
+        }
+
+        String result = stringBuilder.toString();
+
+        return result;
+    }
+
+    // convert string to json
+    @SneakyThrows
+    public JSONObject convertStringToJSON(final String jsonString) {
+        Object obj = parser.parse(jsonString);  // parse json string
+        JSONObject jsonObj = (JSONObject) obj;  // and turn it into a json object
+
+        return jsonObj;
+    }
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/FormatService.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util.service;
+
+import com.onlyoffice.integration.documentserver.models.Format;
+
+import java.util.List;
+
+public interface FormatService {
+    List<Format> getFormats();
+    List<Format> getFormatsByAction(String action);
+    List<String> allExtensions();
+    List<String> fillableExtensions();
+    List<String> viewableExtensions();
+    List<String> editableExtensions();
+    List<String> autoConvertExtensions();
+}

+ 35 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/documentserver/util/service/ServiceConverter.java

@@ -0,0 +1,35 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.documentserver.util.service;
+
+import com.onlyoffice.integration.dto.ConvertedData;
+import org.json.simple.JSONObject;
+
+import java.io.InputStream;
+
+
+// specify the converter service functions
+public interface ServiceConverter {
+    ConvertedData getConvertedData(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
+    JSONObject convertStringToJSON(String jsonString);  // convert string to json
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Action.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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.onlyoffice.integration.documentserver.models.enums.Action type;
+}

+ 31 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ChangesHistory.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ChangesHistory {
+    private String created;
+    private ChangesUser user;
+}

+ 31 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ChangesUser.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ChangesUser {
+    private String id;
+    private String name;
+}

+ 40 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Convert.java

@@ -0,0 +1,40 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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;
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ConvertedData.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ConvertedData {
+    private String uri;
+    private String fileType;
+}

+ 36 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Converter.java

@@ -0,0 +1,36 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/History.java

@@ -0,0 +1,40 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.onlyoffice.integration.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
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Mentions.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class Mentions {
+    private String name;
+    private String email;
+}

+ 32 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Protect.java

@@ -0,0 +1,32 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class Protect {
+    private Integer id;
+    private String name;
+    private String email;
+}

+ 37 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Reference.java

@@ -0,0 +1,37 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Reference {
+    private Boolean directUrl;
+    private ReferenceData referenceData;
+    private String path;
+    private String link;
+}

+ 31 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/ReferenceData.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ReferenceData {
+    private String fileKey;
+    private String instanceId;
+}

+ 34 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Rename.java

@@ -0,0 +1,34 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Rename {
+    private String fileName;
+    private String fileKey;
+    private String fileType;
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Restore.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Restore {
+    private String fileName;
+    private Integer version;
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/SaveAs.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class SaveAs {
+    private String title;
+    private String url;
+}

+ 47 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/Track.java

@@ -0,0 +1,47 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.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;
+    private String formsdataurl;
+}

+ 33 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/dto/UserInfo.java

@@ -0,0 +1,33 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class UserInfo {
+    private Integer id;
+    private String name;
+    private String email;
+    private String image;
+}

+ 41 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/AbstractEntity.java

@@ -0,0 +1,41 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.entities;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import java.io.Serializable;
+
+@MappedSuperclass
+@NoArgsConstructor
+@AllArgsConstructor
+@Setter
+@Getter
+public abstract class AbstractEntity implements Serializable {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private int id;
+}

+ 39 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/Group.java

@@ -0,0 +1,39 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.entities;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import java.util.List;
+
+@Entity
+@Table(name = "`group`")
+@Getter
+@Setter
+public class Group extends AbstractEntity {
+    @Column(unique = true)
+    private String name;
+    @OneToMany(mappedBy = "group")
+    private List<User> users;
+}

+ 56 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/Permission.java

@@ -0,0 +1,56 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.entities;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import java.util.List;
+
+@Entity
+@Table(name = "`permission`")
+@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;
+    private Boolean protect = true;
+}

+ 45 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/entities/User.java

@@ -0,0 +1,45 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.entities;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.*;
+import java.util.List;
+
+@Entity
+@Table(name = "`user`")
+@Getter
+@Setter
+public class User extends AbstractEntity {
+    private String name;
+    private String email;
+    private Boolean favorite;
+    @ManyToOne
+    private Group group;
+    @OneToOne
+    private Permission permissions;
+//    @Column(columnDefinition = "CLOB")
+    @ElementCollection
+    @CollectionTable(name = "user_descriptions")
+    private List<String> descriptions;
+    private Boolean avatar;
+    private String image;
+}

+ 58 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/AbstractMapper.java

@@ -0,0 +1,58 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.mappers;
+
+import com.onlyoffice.integration.documentserver.models.AbstractModel;
+import com.onlyoffice.integration.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
+    private ModelMapper mapper;
+
+    private Class<M> modelClass;
+
+    AbstractMapper(final Class<M> modelClassParam) {
+        this.modelClass = modelClassParam;
+    }
+
+    @Override
+    public M toModel(final 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(final E source, final M destination) {
+    }
+}

+ 27 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/Mapper.java

@@ -0,0 +1,27 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.mappers;
+
+import com.onlyoffice.integration.documentserver.models.AbstractModel;
+import com.onlyoffice.integration.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
+}

+ 69 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/PermissionsMapper.java

@@ -0,0 +1,69 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.mappers;
+
+import com.onlyoffice.integration.documentserver.models.filemodel.CommentGroup;
+import com.onlyoffice.integration.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;
+import java.util.stream.Collectors;
+
+@Component
+@Primary
+public class PermissionsMapper extends AbstractMapper<Permission,
+        com.onlyoffice.integration.documentserver.models.filemodel.Permission> {
+    @Autowired
+    private ModelMapper mapper;
+
+    public PermissionsMapper() {
+        super(com.onlyoffice.integration.documentserver.models.filemodel.Permission.class);
+    }
+
+    @PostConstruct
+    public void configure() {  // configure the permission mapper
+        mapper.createTypeMap(Permission.class, com.onlyoffice.integration.documentserver.models.filemodel
+                        .Permission.class)  // create the type map
+                .setPostConverter(modelConverter());  // and apply the post converter to it
+    }
+
+    @Override
+    void handleSpecificFields(final Permission source,
+                              final com.onlyoffice.integration.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
+
+        // set the commentGroups parameter
+        destination.setCommentGroups(
+                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()));
+    }
+}

+ 53 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/mappers/UsersMapper.java

@@ -0,0 +1,53 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.mappers;
+
+import com.onlyoffice.integration.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.onlyoffice.integration.documentserver.models.filemodel.User> {
+    @Autowired
+    private ModelMapper mapper;
+
+    public UsersMapper() {
+        super(com.onlyoffice.integration.documentserver.models.filemodel.User.class);
+    }
+
+    @PostConstruct
+    public void configure() {  // configure the users mapper
+        mapper.createTypeMap(User.class, com.onlyoffice.integration.documentserver.models.filemodel
+                        .User.class)  // create the type map
+                .setPostConverter(modelConverter());  // and apply the post converter to it
+    }
+
+    @Override
+    public void handleSpecificFields(final User source,
+                                     final com.onlyoffice.integration.documentserver.models.filemodel
+                                             .User destination) {  // handle specific users fields
+        destination.setGroup(source.getGroup() != null
+                ? source.getGroup().getName() : null);  // set the Group parameter
+    }
+}

+ 62 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/GroupServices.java

@@ -0,0 +1,62 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services;
+
+import com.onlyoffice.integration.entities.Group;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class GroupServices {
+
+
+
+    // create a new group with the specified name
+    public Group createGroup(final 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(final List<String> reviewGroups) {
+        if (reviewGroups == null) {
+            return null;  // check if the reviewGroups permission exists
+        }
+        // convert this parameter to a list of groups whose changes the user can accept/reject
+        return reviewGroups.stream()
+                .map(group -> createGroup(group))
+                .collect(Collectors.toList());
+    }
+}

+ 62 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/PermissionServices.java

@@ -0,0 +1,62 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services;
+
+import com.onlyoffice.integration.entities.Group;
+import com.onlyoffice.integration.entities.Permission;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class PermissionServices {
+
+
+    // create permissions with the specified parameters
+    public Permission createPermission(final List<Group> reviewGroups,
+                                       final List<Group> commentViewGroups,
+                                       final List<Group> commentEditGroups,
+                                       final List<Group> commentRemoveGroups,
+                                       final List<Group> userInfoGroups,
+                                       final Boolean chat,
+                                       final Boolean protect) {
+
+        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);
+        permission.setProtect(protect);
+
+//        permissionRepository.save(permission);  // save new permissions
+
+        return permission;
+    }
+
+    // update permissions
+    public Permission updatePermission(final Permission newPermission) {
+//        permissionRepository.save(newPermission);  // save new permissions
+
+        return newPermission;
+    }
+}

+ 93 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/UserServices.java

@@ -0,0 +1,93 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services;
+
+import com.onlyoffice.integration.entities.Group;
+import com.onlyoffice.integration.entities.Permission;
+import com.onlyoffice.integration.entities.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class UserServices {
+
+    @Autowired
+    private GroupServices groupServices;
+
+    @Autowired
+    private PermissionServices permissionService;
+
+    // get a list of all users
+    public List<User> findAll() {
+        return new ArrayList<>();
+    }
+
+    // get a user by their ID
+    public Optional<User> findUserById(final Integer id) {
+        return Optional.of(new User());
+    }
+
+    // create a user with the specified parameters
+    public User createUser(final String name, final String email,
+                           final List<String> description, final String group,
+                           final List<String> reviewGroups,
+                           final List<String> viewGroups,
+                           final List<String> editGroups,
+                           final List<String> removeGroups,
+                           final List<String> userInfoGroups, final Boolean favoriteDoc,
+                           final Boolean chat,
+                           final Boolean protect,
+                           final Boolean avatar) {
+        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
+        newUser.setAvatar(avatar);
+
+        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,
+                        protect);  // specify permissions for the current user
+        newUser.setPermissions(permission);
+
+//        userRepository.save(newUser); // save a new user
+
+        return newUser;
+    }
+}

+ 23 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/Configurer.java

@@ -0,0 +1,23 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers;
+
+public interface Configurer<O, W> {
+    void configure(O instance, W wrapper);
+}

+ 25 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/CustomizationConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers;
+
+import com.onlyoffice.integration.documentserver.models.configurations.Customization;
+
+public interface CustomizationConfigurer<W> extends Configurer<Customization, W> {
+    void configure(Customization customization, W wrapper);
+}

+ 25 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/DocumentConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers;
+
+import com.onlyoffice.integration.documentserver.models.filemodel.Document;
+
+public interface DocumentConfigurer<W> extends Configurer<Document, W> {
+    void configure(Document document, W wrapper);
+}

+ 25 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/EditorConfigConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers;
+
+import com.onlyoffice.integration.documentserver.models.filemodel.EditorConfig;
+
+public interface EditorConfigConfigurer<W> extends Configurer<EditorConfig, W> {
+    void configure(EditorConfig editorConfig, W wrapper);
+}

+ 25 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/EmbeddedConfigurer.java

@@ -0,0 +1,25 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers;
+
+import com.onlyoffice.integration.documentserver.models.configurations.Embedded;
+
+public interface EmbeddedConfigurer<W> extends Configurer<Embedded, W> {
+    void configure(Embedded embedded, W wrapper);
+}

+ 26 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/FileConfigurer.java

@@ -0,0 +1,26 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers;
+
+import com.onlyoffice.integration.documentserver.models.filemodel.FileModel;
+
+public interface FileConfigurer<W> extends Configurer<FileModel, W> {
+    void configure(FileModel model, W wrapper);
+    FileModel getFileModel(W wrapper);
+}

+ 38 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultCustomizationConfigurer.java

@@ -0,0 +1,38 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.implementations;
+
+import com.onlyoffice.integration.documentserver.models.configurations.Customization;
+import com.onlyoffice.integration.documentserver.models.enums.Action;
+import com.onlyoffice.integration.entities.User;
+import com.onlyoffice.integration.services.configurers.CustomizationConfigurer;
+import com.onlyoffice.integration.services.configurers.wrappers.DefaultCustomizationWrapper;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+@Service
+@Primary
+public class DefaultCustomizationConfigurer implements CustomizationConfigurer<DefaultCustomizationWrapper> {
+    @Override
+    // define the customization configurer
+    public void configure(final Customization customization, final DefaultCustomizationWrapper wrapper) {
+        Action action = wrapper.getAction();  // get the action parameter from the customization wrapper
+        User user = wrapper.getUser();
+    }
+}

+ 93 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultDocumentConfigurer.java

@@ -0,0 +1,93 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.implementations;
+
+import com.google.gson.Gson;
+import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
+import com.onlyoffice.integration.documentserver.models.filemodel.Document;
+import com.onlyoffice.integration.documentserver.models.filemodel.Permission;
+import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
+import com.onlyoffice.integration.services.configurers.DocumentConfigurer;
+import com.onlyoffice.integration.services.configurers.wrappers.DefaultDocumentWrapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.util.HashMap;
+
+@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(final Document document,
+                          final DefaultDocumentWrapper wrapper) {  // define the document configurer
+        String fileName = wrapper.getFileName();  // 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
+
+        // set the URL to download a file to the document config
+        document.setUrl(documentManager.getDownloadUrl(fileName, true));
+        document.setUrlUser(documentManager
+                .getFileUri(fileName, false));  // set the file URL to the document config
+        document.setDirectUrl(wrapper.getIsEnableDirectUrl() ? documentManager
+                .getDownloadUrl(fileName, false) : "");
+        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
+
+        // get the document key
+        String key = serviceConverter
+                .generateRevisionId(storagePathBuilder.getStorageLocation()
+                        + "/" + fileName + "/"
+                        + new File(storagePathBuilder.getFileLocation(fileName)).lastModified());
+
+        Gson gson = new Gson();
+        HashMap<String, String> fileKey = new HashMap<>();
+        fileKey.put("fileName", fileName);
+        try {
+            fileKey.put("userAddress", InetAddress.getLocalHost().getHostAddress());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        HashMap<String, Object> referenceData = new HashMap<>();
+        referenceData.put("instanceId", storagePathBuilder.getServerUrl(true));
+        referenceData.put("fileKey", gson.toJson(fileKey));
+
+        document.setKey(key);  // set the key to the document config
+        document.setPermissions(permission);  // set the permission parameters to the document config
+        document.setReferenceData(referenceData);
+    }
+}

+ 112 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultEditorConfigConfigurer.java

@@ -0,0 +1,112 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.implementations;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.reflect.TypeToken;
+import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
+import com.onlyoffice.integration.documentserver.managers.template.TemplateManager;
+import com.onlyoffice.integration.documentserver.models.enums.Action;
+import com.onlyoffice.integration.documentserver.models.enums.Mode;
+import com.onlyoffice.integration.documentserver.models.filemodel.EditorConfig;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.entities.User;
+import com.onlyoffice.integration.mappers.Mapper;
+import com.onlyoffice.integration.services.configurers.EditorConfigConfigurer;
+import com.onlyoffice.integration.services.configurers.wrappers.DefaultCustomizationWrapper;
+import com.onlyoffice.integration.services.configurers.wrappers.DefaultEmbeddedWrapper;
+import com.onlyoffice.integration.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.onlyoffice.integration.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(final EditorConfig config,
+                          final DefaultFileWrapper wrapper) {  // define the editorConfig configurer
+        if (wrapper.getActionData() != null) {  // check if the actionData is not empty in the editorConfig wrapper
+
+            // set actionLink to the editorConfig
+            config.setActionLink(objectMapper.readValue(wrapper.getActionData(),
+                    (JavaType) new TypeToken<HashMap<String, Object>>() { }.getType()));
+        }
+        String fileName = wrapper.getFileName();  // set the fileName parameter from the editorConfig wrapper
+        boolean userIsAnon = wrapper.getUser()
+                .getName().equals("Anonymous");  // check if the user from the editorConfig wrapper is anonymous or not
+
+        // set a template to the editorConfig if the user is not anonymous
+        config.setTemplates(userIsAnon ? null : templateManager.createTemplates(fileName));
+        config.setCallbackUrl(documentManager.getCallback(fileName));  // set the callback URL to the editorConfig
+
+        // set the document URL where it will be created to the editorConfig if the user is not anonymous
+        config.setCreateUrl(userIsAnon ? null : documentManager.getCreateUrl(fileName, false));
+        config.setLang("zh");  // 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);
+        }} : null);
+
+        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());
+
+        config.getPlugins().getAutostart().add("asc.{0616AE85-5DBE-4B6B-A0A9-455C4F1503AD}");
+        config.getPlugins().getPluginsData().add("http://192.168.56.164:9999/8.1.3-4/sdkjs-plugins/helloworld/config.json");
+    }
+}

+ 61 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultEmbeddedConfigurer.java

@@ -0,0 +1,61 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.implementations;
+
+import com.onlyoffice.integration.documentserver.managers.document.DocumentManager;
+import com.onlyoffice.integration.documentserver.models.configurations.Embedded;
+import com.onlyoffice.integration.documentserver.models.enums.ToolbarDocked;
+import com.onlyoffice.integration.documentserver.models.enums.Type;
+import com.onlyoffice.integration.services.configurers.EmbeddedConfigurer;
+import com.onlyoffice.integration.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(final Embedded embedded,
+                          final 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
+
+            /* 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.setEmbedUrl(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.setSaveUrl(url);
+
+            /* set the shareURL parameter to the embedded config (the absolute URL
+             that will allow other users to share this document) */
+            embedded.setShareUrl(url);
+
+            /* set the top toolbarDocked parameter to the embedded config (the place for the
+             embedded viewer toolbar, can be either top or bottom) */
+            embedded.setToolbarDocked(ToolbarDocked.top);
+        }
+    }
+}

+ 137 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/implementations/DefaultFileConfigurer.java

@@ -0,0 +1,137 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.implementations;
+
+import com.onlyoffice.integration.documentserver.managers.jwt.JwtManager;
+import com.onlyoffice.integration.documentserver.models.enums.Action;
+import com.onlyoffice.integration.documentserver.models.enums.DocumentType;
+import com.onlyoffice.integration.documentserver.models.filemodel.FileModel;
+import com.onlyoffice.integration.documentserver.models.filemodel.Permission;
+import com.onlyoffice.integration.documentserver.util.file.FileUtility;
+import com.onlyoffice.integration.mappers.Mapper;
+import com.onlyoffice.integration.services.configurers.FileConfigurer;
+import com.onlyoffice.integration.services.configurers.wrappers.DefaultDocumentWrapper;
+import com.onlyoffice.integration.services.configurers.wrappers.DefaultFileWrapper;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+@Primary
+public class DefaultFileConfigurer implements FileConfigurer<DefaultFileWrapper> {
+    @Autowired
+    private ObjectFactory<FileModel> fileModelObjectFactory;
+
+    @Autowired
+    private FileUtility fileUtility;
+
+    @Autowired
+    private JwtManager jwtManager;
+
+    @Autowired
+    private Mapper<com.onlyoffice.integration.entities.Permission, Permission> mapper;
+
+    @Autowired
+    private DefaultDocumentConfigurer defaultDocumentConfigurer;
+
+    @Autowired
+    private DefaultEditorConfigConfigurer defaultEditorConfigConfigurer;
+
+    public void configure(final FileModel fileModel, final DefaultFileWrapper wrapper) {  // define the file configurer
+        if (fileModel != null) {  // check if the file model is specified
+            String fileName = wrapper.getFileName();  // get the fileName parameter from the file wrapper
+            Action action = wrapper.getAction();  // get the action parameter from the file wrapper
+
+            DocumentType documentType = fileUtility
+                    .getDocumentType(fileName);  // get the document type of the specified file
+            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
+
+            String fileExt = fileUtility.getFileExtension(wrapper.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()
+                    .fileName(fileName)
+                    .permission(updatePermissions(userPermissions, action, canEdit))
+                    .favorite(wrapper.getUser().getFavorite())
+                    .isEnableDirectUrl(wrapper.getIsEnableDirectUrl())
+                    .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(final DefaultFileWrapper wrapper) {  // get file model
+        FileModel fileModel = fileModelObjectFactory.getObject();
+        configure(fileModel, wrapper);  // and configure it
+        return fileModel;
+    }
+
+    private Permission updatePermissions(final Permission userPermissions, final Action action, final 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.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
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultCustomizationWrapper.java

@@ -0,0 +1,31 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.wrappers;
+
+import com.onlyoffice.integration.documentserver.models.enums.Action;
+import com.onlyoffice.integration.entities.User;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class DefaultCustomizationWrapper {
+    private Action action;
+    private User user;
+}

+ 34 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultDocumentWrapper.java

@@ -0,0 +1,34 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.wrappers;
+
+import com.onlyoffice.integration.documentserver.models.filemodel.Permission;
+import com.onlyoffice.integration.documentserver.models.filemodel.ReferenceData;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class DefaultDocumentWrapper {
+    private Permission permission;
+    private String fileName;
+    private Boolean favorite;
+    private Boolean isEnableDirectUrl;
+    private ReferenceData referenceData;
+}

+ 30 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultEmbeddedWrapper.java

@@ -0,0 +1,30 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.wrappers;
+
+import com.onlyoffice.integration.documentserver.models.enums.Type;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class DefaultEmbeddedWrapper {
+    private Type type;
+    private String fileName;
+}

+ 40 - 0
ibps-provider-root/modules/provider-business/src/main/java/com/onlyoffice/integration/services/configurers/wrappers/DefaultFileWrapper.java

@@ -0,0 +1,40 @@
+/**
+ *
+ * (c) Copyright Ascensio System SIA 2024
+ *
+ * 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.onlyoffice.integration.services.configurers.wrappers;
+
+import com.onlyoffice.integration.documentserver.models.enums.Action;
+import com.onlyoffice.integration.documentserver.models.enums.Type;
+import com.onlyoffice.integration.entities.User;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Builder
+@Setter
+public class DefaultFileWrapper {
+    private String fileName;
+    private Type type;
+    private User user;
+    private String lang;
+    private Action action;
+    private String actionData;
+    private Boolean canEdit;
+    private Boolean isEnableDirectUrl;
+}