mirror of
https://github.com/ONLYOFFICE/document-server-integration.git
synced 2026-04-07 14:06:11 +08:00
Compare commits
228 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 01e79b6bb9 | |||
| 95060d2e4b | |||
| 79da267a9c | |||
| 3cf0e897df | |||
| 1109f35376 | |||
| 6546a51f17 | |||
| 685a62bb9c | |||
| 2603acae16 | |||
| 11489ac8ba | |||
| e65f6f27be | |||
| a0a1b036e3 | |||
| f846197396 | |||
| 97f95fb850 | |||
| 7d8a1a8b6d | |||
| 23389056e8 | |||
| 457e38c35a | |||
| 11075304a5 | |||
| 7af14e75e8 | |||
| c8ccb3b502 | |||
| 449ad0759b | |||
| 32e4cb6d64 | |||
| 83b1dc07e1 | |||
| b61e05d203 | |||
| 9cf058078c | |||
| d72834687e | |||
| af1dc6d9b5 | |||
| e5560b25d7 | |||
| d894663a4a | |||
| b262a34540 | |||
| 3d0ae07de4 | |||
| efb4616ca6 | |||
| 037c5682f8 | |||
| 7c1939e8c9 | |||
| 6312833dd3 | |||
| ce58acbca9 | |||
| d40f932863 | |||
| d6d1981296 | |||
| b9fc1304d9 | |||
| dac1cdcdc1 | |||
| 248beed471 | |||
| 9d5feaaf99 | |||
| d397db61cd | |||
| 969240ad53 | |||
| 8fd9113c47 | |||
| 068687ba91 | |||
| 495d97bd3a | |||
| 160c0bef3c | |||
| 0b5b0d9c27 | |||
| b903bfc0cb | |||
| 580f8f3e89 | |||
| b19abbcb36 | |||
| 4de6f4d828 | |||
| ad4b2d136c | |||
| 6578d414ea | |||
| 7ca8a2122f | |||
| 9389607aaf | |||
| 3d63728344 | |||
| 40d1c0c03b | |||
| 0c2a271357 | |||
| e94d81e228 | |||
| 4c9c79ae8e | |||
| d51dab82c5 | |||
| 1e66124a8a | |||
| 5fd2878c3d | |||
| 63ec4db0b3 | |||
| 0d3ed49adf | |||
| 7197a216f8 | |||
| 716d4dc694 | |||
| d744bc2e23 | |||
| a69f7f343a | |||
| 10b40423ad | |||
| 4ea23d1677 | |||
| e0ed22d1f5 | |||
| 5148fd2601 | |||
| 97420e18cf | |||
| 10e1848beb | |||
| d4b2bf95bc | |||
| d613a02068 | |||
| 4ff7b6e543 | |||
| 066de3359d | |||
| 4577861f8b | |||
| 94df21fe21 | |||
| af38a4ba61 | |||
| 7e9356df5e | |||
| 5f68d09e2f | |||
| 18aa9487b3 | |||
| f00f212662 | |||
| 743176bb5c | |||
| 58eec51312 | |||
| 1f5c23a2d1 | |||
| 992dbe18af | |||
| ae738e1be2 | |||
| 9796abf846 | |||
| 9471891a89 | |||
| 9b64957189 | |||
| 6f5a854cd2 | |||
| f441ab1650 | |||
| fd5a2b7b0e | |||
| f2504ab740 | |||
| 7710c6d6e8 | |||
| 5b99e3d17a | |||
| 955b35f382 | |||
| 8580ea8a57 | |||
| cba2eac65d | |||
| f5ccc21f69 | |||
| 03a585685e | |||
| 40c520e8fd | |||
| 940b4bfc80 | |||
| 7fe7753c88 | |||
| 8fa40ab439 | |||
| 8f4de5ce0d | |||
| 94d22003b5 | |||
| f8d62ab8db | |||
| f955096fc0 | |||
| 9b0d3e1a20 | |||
| dafc66d5d8 | |||
| 902ad1341c | |||
| 1cd457c5c6 | |||
| 4536f83d10 | |||
| acdb60dd3b | |||
| c5315de84f | |||
| c639ba4287 | |||
| ea15f12551 | |||
| c0135c52c5 | |||
| f87fc045d3 | |||
| 684fa89c13 | |||
| f4d838710c | |||
| 0728a71f01 | |||
| 9cbb946c8f | |||
| 24ff9ce804 | |||
| 498268a7a3 | |||
| 2477fb21c5 | |||
| a809af8eca | |||
| 5f053de539 | |||
| f47f9bf897 | |||
| 7d09d87891 | |||
| 83843342d4 | |||
| a407b2b9c7 | |||
| b29b0c3fa5 | |||
| 821df5c700 | |||
| 56e96eeac1 | |||
| 6525c29107 | |||
| 3197702d7b | |||
| 286fb47fb8 | |||
| 44445de6e7 | |||
| 986eeefb4d | |||
| 12aba3d66d | |||
| 4c92c1c750 | |||
| 4e685d9eab | |||
| bb4e2b3b46 | |||
| d1b972fb18 | |||
| a17819efb2 | |||
| 79b98bed53 | |||
| 27267e2d5b | |||
| de5fc508f2 | |||
| dccc970fa1 | |||
| 5259cc19fa | |||
| 8527ac602f | |||
| 6ff7b4fa8f | |||
| 9747867935 | |||
| 42c2c93e81 | |||
| c0d8e0e339 | |||
| d06bb98a61 | |||
| dd3b7ab077 | |||
| 7d6933803f | |||
| 26fc316cee | |||
| bd922d202e | |||
| c350dd022f | |||
| f3cfdc353e | |||
| 9b010f8315 | |||
| 5171624adc | |||
| 3247a75318 | |||
| 81a43656b2 | |||
| 3df552b4b2 | |||
| e9b4fce50b | |||
| 1989c5f44d | |||
| 23193739f7 | |||
| 21d75418c2 | |||
| b630764daf | |||
| f9375a7414 | |||
| 52d72371d5 | |||
| 519f6d6f32 | |||
| eb6861059e | |||
| f5801a7f8c | |||
| 15b905613c | |||
| 5255f0e462 | |||
| 5e29215a11 | |||
| de32be3945 | |||
| 63c04c85b0 | |||
| 2d3fc72283 | |||
| b6e71e42c1 | |||
| dcf78b13f2 | |||
| d8b0bd55cf | |||
| 8ddbb6ba18 | |||
| 831e59b390 | |||
| 95de0fc2c7 | |||
| b48efac604 | |||
| c0eb1c8a85 | |||
| 118779aac1 | |||
| 276f5c1e20 | |||
| 64f66d4fa3 | |||
| ac3e0faba8 | |||
| fde6a09f75 | |||
| f12fb576d8 | |||
| b5585cf3db | |||
| f1a69218ae | |||
| dbce9946e0 | |||
| 3b66092a45 | |||
| 1b91592a9a | |||
| e9e6586d6d | |||
| 266e249b12 | |||
| ce9d62ad7d | |||
| febce17e86 | |||
| 63b2202f82 | |||
| 7c57b0f575 | |||
| 0494d24e29 | |||
| 9d3d5243b2 | |||
| 440b51c7ff | |||
| 0d3cda32fa | |||
| e5d4be0d61 | |||
| 5f2c5cea58 | |||
| 71215e342f | |||
| 4b822dafe9 | |||
| 39820cec0a | |||
| e9893c7c51 | |||
| fe352ebad1 | |||
| 18cf21efe4 | |||
| 825aafda25 |
14
.github/workflows/lint-python.yml
vendored
14
.github/workflows/lint-python.yml
vendored
@ -21,15 +21,17 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install flake8
|
||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||
make dev
|
||||
|
||||
- name: Lint Flake8
|
||||
run: |
|
||||
flake8 --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
flake8 --count --max-complexity=15 --max-line-length=120 --per-file-ignores="__init__.py:F4" --statistics
|
||||
make lint
|
||||
|
||||
# TODO: Configure mypy
|
||||
# - name: Types mypy
|
||||
# run: |
|
||||
# make types
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -5,7 +5,7 @@
|
||||
[submodule "web/documentserver-example/nodejs/public/assets/document-formats"]
|
||||
path = web/documentserver-example/nodejs/public/assets/document-formats
|
||||
url = https://github.com/ONLYOFFICE/document-formats
|
||||
branch = master
|
||||
branch = feature/v8.0
|
||||
[submodule "web/documentserver-example/csharp-mvc/assets/document-templates"]
|
||||
path = web/documentserver-example/csharp-mvc/assets/document-templates
|
||||
url = https://github.com/ONLYOFFICE/document-templates
|
||||
|
||||
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,10 +1,11 @@
|
||||
# Change Log
|
||||
|
||||
- link in referenceData
|
||||
- version number to page meta
|
||||
- sr-Latn-CS skin languages
|
||||
- getting history via api
|
||||
- using a repo with a list of formats
|
||||
- ruby: convert after uploading only tagged formats
|
||||
- python: convert after uploading only tagged formats
|
||||
- php: convert after uploading only tagged formats
|
||||
- convert after uploading only tagged formats
|
||||
- link in referenceData
|
||||
- setUsers for region protection
|
||||
- onRequestOpen method
|
||||
- user avatar
|
||||
@ -13,8 +14,6 @@
|
||||
- onRequestSelectSpreadsheet method
|
||||
- key in referenceData
|
||||
- restore from history
|
||||
- java: getting history by a separate request
|
||||
- java-spring: getting history by a separate request
|
||||
|
||||
## 1.7.0
|
||||
- nodejs: onRequestSelectDocument method
|
||||
|
||||
@ -31,6 +31,12 @@ namespace OnlineEditorsExampleMVC.Helpers
|
||||
{
|
||||
public class DocManagerHelper
|
||||
{
|
||||
//get server version
|
||||
public static string GetVersion()
|
||||
{
|
||||
return WebConfigurationManager.AppSettings["version"];
|
||||
}
|
||||
|
||||
// get max file size
|
||||
public static long MaxFileSize
|
||||
{
|
||||
|
||||
@ -126,9 +126,7 @@ namespace OnlineEditorsExampleMVC.Models
|
||||
public static List<Format> Convertible()
|
||||
{
|
||||
return All()
|
||||
.Where(format => (format.Type == FileType.Cell && format.Convert.Contains("xlsx"))
|
||||
|| (format.Type == FileType.Slide && format.Convert.Contains("pptx"))
|
||||
|| (format.Type == FileType.Word && format.Convert.Contains("docx")))
|
||||
.Where(format => format.Actions.Contains("auto-convert"))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content=<%= DocManagerHelper.GetVersion() %> />
|
||||
<!--
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2023
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
<add key="files.docservice.verify-peer-off" value="true"/>
|
||||
|
||||
<add key="files.docservice.languages" value="en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
|
||||
<add key="files.docservice.languages" value="en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
|
||||
|
||||
<add key="files.docservice.url.site" value="http://documentserver/"/>
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
<head runat="server">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content=<%= GetVersion() %> />
|
||||
<title>ONLYOFFICE</title>
|
||||
<!--
|
||||
*
|
||||
|
||||
@ -33,6 +33,12 @@ namespace OnlineEditorsExample
|
||||
public partial class _Default : Page
|
||||
{
|
||||
|
||||
//get server version
|
||||
public static string GetVersion()
|
||||
{
|
||||
return WebConfigurationManager.AppSettings["version"];
|
||||
}
|
||||
|
||||
// get the virtual path
|
||||
public static string VirtualPath
|
||||
{
|
||||
|
||||
@ -104,9 +104,7 @@ namespace OnlineEditorsExample
|
||||
public static List<Format> Convertible()
|
||||
{
|
||||
return All()
|
||||
.Where(format => (format.Type == "cell" && format.Convert.Contains("xlsx"))
|
||||
|| (format.Type == "slide" && format.Convert.Contains("pptx"))
|
||||
|| (format.Type == "word" && format.Convert.Contains("docx")))
|
||||
.Where(format => format.Actions.Contains("auto-convert"))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
<add key="files.docservice.token.useforrequest" value="true" />
|
||||
|
||||
<add key="files.docservice.languages" value="en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
|
||||
<add key="files.docservice.languages" value="en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA: Test Language"/>
|
||||
|
||||
<add key="files.docservice.url.site" value="http://documentserver/"/>
|
||||
|
||||
|
||||
@ -76,6 +76,9 @@ public class IndexController {
|
||||
@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) {
|
||||
@ -124,6 +127,7 @@ public class IndexController {
|
||||
model.addAttribute("users", users);
|
||||
model.addAttribute("languages", languages);
|
||||
model.addAttribute("directUrl", directUrl);
|
||||
model.addAttribute("serverVersion", serverVersion);
|
||||
|
||||
return "index.html";
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
// todo: Rebuild completely
|
||||
@Component
|
||||
@ -280,8 +281,9 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
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(i - 1));
|
||||
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
|
||||
@ -292,10 +294,12 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
|
||||
// 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(fileName, verdiff, "diff.zip", true));
|
||||
|
||||
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()) {
|
||||
@ -331,4 +335,11 @@ public class DefaultHistoryManager implements HistoryManager {
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ files.docservice.token-use-for-request=true
|
||||
|
||||
files.docservice.verify-peer-off=true
|
||||
|
||||
files.docservice.languages=en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
|
||||
files.docservice.languages=en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
|
||||
|
||||
spring.datasource.url=jdbc:h2:mem:usersdb
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" th:content="${serverVersion}"/>
|
||||
<!--
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2023
|
||||
|
||||
@ -995,9 +995,10 @@ public class IndexServlet extends HttpServlet {
|
||||
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(i - 1));
|
||||
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"));
|
||||
|
||||
@ -1010,12 +1011,16 @@ public class IndexServlet extends HttpServlet {
|
||||
|
||||
// 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;
|
||||
String changesUrl = DocumentManager
|
||||
.getDownloadHistoryUrl(fileName, verdiff,
|
||||
"diff.zip", true);
|
||||
dataObj.put("changesUrl", changesUrl);
|
||||
|
||||
String diffPath = Paths.get(histDir, String.valueOf(verdiff), "diff.zip").toString();
|
||||
File diffFile = new File(diffPath);
|
||||
if (diffFile.exists()) {
|
||||
// write the path to the diff.zip archive with differences in this file version
|
||||
String changesUrl = DocumentManager
|
||||
.getDownloadHistoryUrl(fileName, verdiff,
|
||||
"diff.zip", true);
|
||||
dataObj.put("changesUrl", changesUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (DocumentManager.tokenEnabled()) {
|
||||
|
||||
@ -13,7 +13,7 @@ files.docservice.url.api=web-apps/apps/api/documents/api.js
|
||||
files.docservice.url.preloader=web-apps/apps/api/documents/cache-scripts.html
|
||||
files.docservice.url.example=
|
||||
|
||||
files.docservice.languages=en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
|
||||
files.docservice.languages=en:English|hy:Armenian|az:Azerbaijani|eu:Basque|be:Belarusian|bg:Bulgarian|ca:Catalan|zh:Chinese (Simplified)|zh-TW:Chinese (Traditional)|cs:Czech|da:Danish|nl:Dutch|fi:Finnish|fr:French|gl:Galego|de:German|el:Greek|hu:Hungarian|id:Indonesian|it:Italian|ja:Japanese|ko:Korean|lo:Lao|lv:Latvian|ms:Malay (Malaysia)|no:Norwegian|pl:Polish|pt:Portuguese (Brazil)|pt-PT:Portuguese (Portugal)|ro:Romanian|ru:Russian|sr-Latn-CS:Serbian|si:Sinhala (Sri Lanka)|sk:Slovak|sl:Slovenian|es:Spanish|sv:Swedish|tr:Turkish|uk:Ukrainian|vi:Vietnamese|aa-AA:Test Language
|
||||
|
||||
files.docservice.secret=
|
||||
files.docservice.header=Authorization
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content="<%= ConfigManager.getProperty("version") %>" />
|
||||
<!--
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2023
|
||||
|
||||
@ -55,7 +55,7 @@ String.prototype.hashCode = function hashCode() {
|
||||
const len = this.length;
|
||||
let ret = 0;
|
||||
for (let i = 0; i < len; i++) {
|
||||
ret = Math.trunc(31 * ret + this.charCodeAt(i));
|
||||
ret = Math.imul(ret, 31) + this.charCodeAt(i);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
@ -100,6 +100,7 @@ app.get('/', (req, res) => { // define a handler for default page
|
||||
params: req.DocManager.getCustomParams(),
|
||||
users,
|
||||
languages: configServer.get('languages'),
|
||||
serverVersion: config.get('version'),
|
||||
});
|
||||
} catch (ex) {
|
||||
console.log(ex); // display error message in the console
|
||||
@ -993,19 +994,27 @@ app.get('/editor', (req, res) => { // define a handler for editing document
|
||||
if (!canEdit && mode === 'edit') {
|
||||
mode = 'view';
|
||||
}
|
||||
const submitForm = mode === 'fillForms' && userid === 'uid-1';
|
||||
|
||||
let submitForm = false;
|
||||
const ext = fileUtility.getFileExtension(fileName, true);
|
||||
let isForm = 'null';
|
||||
if (mode === 'fillForms') {
|
||||
submitForm = userid === 'uid-1';
|
||||
isForm = req.DocManager.isExtendedPDFFile(fileName);
|
||||
}
|
||||
|
||||
// file config data
|
||||
const argss = {
|
||||
apiUrl: siteUrl + configServer.get('apiUrl'),
|
||||
file: {
|
||||
name: fileName,
|
||||
ext: fileUtility.getFileExtension(fileName, true),
|
||||
ext: ext,
|
||||
uri: url,
|
||||
directUrl: !userDirectUrl ? null : directUrl,
|
||||
uriUser: directUrl,
|
||||
created: new Date().toDateString(),
|
||||
favorite: user.favorite != null ? user.favorite : 'null',
|
||||
isForm: isForm,
|
||||
},
|
||||
editor: {
|
||||
type,
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"storagePath": "/files",
|
||||
"maxFileSize": 1073741824,
|
||||
"maxNameLength": 50,
|
||||
"gFormatOformPdfMetaTag": "ONLYOFFICEFORM",
|
||||
"mobileRegEx": "android|avantgo|playbook|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino",
|
||||
"token": {
|
||||
"enable": false,
|
||||
@ -69,6 +70,7 @@
|
||||
"pt-PT": "Portuguese (Portugal)",
|
||||
"ro": "Romanian",
|
||||
"ru": "Russian",
|
||||
"sr-Latn-CS": "Serbian",
|
||||
"si": "Sinhala (Sri Lanka)",
|
||||
"sk": "Slovak",
|
||||
"sl": "Slovenian",
|
||||
|
||||
@ -381,6 +381,10 @@ DocManager.prototype.getInternalExtension = function getInternalExtension(fileTy
|
||||
return '.pptx';
|
||||
}
|
||||
|
||||
if (fileType === fileUtility.fileType.pdf) { // .pptx for pdf type
|
||||
return '.pdf';
|
||||
}
|
||||
|
||||
return '.docx'; // the default value is .docx
|
||||
};
|
||||
|
||||
@ -606,6 +610,58 @@ DocManager.prototype.getFilesInfo = function getFilesInfo(fileId) {
|
||||
} return responseArray;
|
||||
};
|
||||
|
||||
DocManager.prototype.isExtendedPDFFile = function isExtendedPDFFile(fileName) {
|
||||
let filePath = this.forcesavePath(fileName, null, false);
|
||||
if (filePath === '') {
|
||||
filePath = this.storagePath(fileName);
|
||||
}
|
||||
|
||||
const bufferSize = 110;
|
||||
const buffer = Buffer.alloc(bufferSize);
|
||||
const fd = fileSystem.openSync(filePath, 'r');
|
||||
|
||||
fileSystem.readSync(fd, buffer, 0, bufferSize);
|
||||
|
||||
const pBuffer = buffer.toString('latin1');
|
||||
|
||||
const indexFirst = pBuffer.indexOf('%\xCD\xCA\xD2\xA9\x0D');
|
||||
if (indexFirst === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let pFirst = pBuffer.substring(indexFirst + 6);
|
||||
|
||||
if (!pFirst.startsWith('1 0 obj\x0A<<\x0A')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pFirst = pFirst.substring(11);
|
||||
|
||||
const indexStream = pFirst.indexOf('stream\x0D\x0A');
|
||||
const indexMeta = pFirst.indexOf(configServer.get('gFormatOformPdfMetaTag'));
|
||||
|
||||
if (indexStream === -1 || indexMeta === -1 || indexStream < indexMeta) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let pMeta = pFirst.substring(indexMeta);
|
||||
pMeta = pMeta.substring(configServer.get('gFormatOformPdfMetaTag').length + 3);
|
||||
|
||||
let indexMetaLast = pMeta.indexOf(' ');
|
||||
if (indexMetaLast === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pMeta = pMeta.substring(indexMetaLast + 1);
|
||||
|
||||
indexMetaLast = pMeta.indexOf(' ');
|
||||
if (indexMetaLast === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
DocManager.prototype.getInstanceId = function getInstanceId() {
|
||||
return this.getServerUrl();
|
||||
};
|
||||
|
||||
@ -64,6 +64,7 @@ fileUtility.fileType = {
|
||||
word: 'word',
|
||||
cell: 'cell',
|
||||
slide: 'slide',
|
||||
pdf: 'pdf',
|
||||
};
|
||||
|
||||
fileUtility.getSuppotredExtensions = function getSuppotredExtensions() {
|
||||
|
||||
@ -0,0 +1 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 1h8l4 4v10H2V1z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14 5l-4-4H2v14h12V5zm-4-5l5 5v11H1V0h9z" fill="#BFBFBF"/><path fill="#9E1919" d="M3 10h10v4H3z"/><path d="M7 7V2H3v5h4zM8 3V2h2v1H8zM8 5V4h5v1H8zM13 6H8v1h5V6zM13 8H3v1h10V8z" fill="#BFBFBF"/><path opacity=".3" d="M9 1h1v3h4l1 1H9V1z" fill="#333"/></svg>
|
||||
|
After Width: | Height: | Size: 441 B |
BIN
web/documentserver-example/nodejs/public/images/pdf.ico
Normal file
BIN
web/documentserver-example/nodejs/public/images/pdf.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
@ -470,6 +470,11 @@ footer table tr td:first-child {
|
||||
background-image: url("../images/icon_pptx.svg");
|
||||
}
|
||||
|
||||
.stored-edit.pdf,
|
||||
.uploadFileName.pdf {
|
||||
background-image: url("../images/icon_pdf.svg");
|
||||
}
|
||||
|
||||
.stored-edit span {
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
"uploaded": "<%- file.created %>",
|
||||
"favorite": <%- file.favorite %>
|
||||
},
|
||||
"isForm": <%- file.isForm %>,
|
||||
"key": "<%- editor.key %>",
|
||||
"permissions": {
|
||||
"chat": <%- editor.chat %>,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content="<%= serverVersion %>">
|
||||
<!--
|
||||
*
|
||||
* (c) Copyright Ascensio System SIA 2023
|
||||
|
||||
@ -103,6 +103,11 @@ function routers()
|
||||
echo json_encode($response);
|
||||
return;
|
||||
}
|
||||
if (str_starts_with($path, '/objhistory')) {
|
||||
$response = historyObj();
|
||||
echo json_encode($response);
|
||||
return;
|
||||
}
|
||||
if (str_starts_with($path, '/reference')) {
|
||||
$response = reference();
|
||||
$response['status'] = 'success';
|
||||
|
||||
@ -380,6 +380,18 @@ function historyDownload()
|
||||
}
|
||||
}
|
||||
|
||||
function historyObj()
|
||||
{
|
||||
$input = file_get_contents('php://input');
|
||||
$body = json_decode($input, true);
|
||||
$fileName = $body['fileName'];
|
||||
$filetype = mb_strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
|
||||
$docKey = getDocEditorKey($fileName);
|
||||
$fileuri = fileUri($fileName, true);
|
||||
$historyObject = getHistory($fileName, $filetype, $docKey, $fileuri, false);
|
||||
return $historyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a file
|
||||
*
|
||||
|
||||
@ -24,6 +24,11 @@ class ConfigurationManager
|
||||
{
|
||||
public string $version = '1.7.0';
|
||||
|
||||
public function getVersion(): string
|
||||
{
|
||||
return $this -> version;
|
||||
}
|
||||
|
||||
public function exampleURL(): ?URL
|
||||
{
|
||||
$url = getenv('EXAMPLE_URL');
|
||||
@ -189,6 +194,7 @@ class ConfigurationManager
|
||||
'pt-PT' => 'Portuguese (Portugal)',
|
||||
'ro' => 'Romanian',
|
||||
'ru' => 'Russian',
|
||||
'sr-Latn-CS' => 'Serbian',
|
||||
'si' => 'Sinhala (Sri Lanka)',
|
||||
'sk' => 'Slovak',
|
||||
'sl' => 'Slovenian',
|
||||
|
||||
@ -951,8 +951,11 @@ function getHistory($filename, $filetype, $docKey, $fileuri, $isEnableDirectUrl)
|
||||
"url" => $prev["url"],
|
||||
];
|
||||
|
||||
// write the path to the diff.zip archive with differences in this file version
|
||||
$dataObj["changesUrl"] = getHistoryDownloadUrl($filename, $i - 1, "diff.zip");
|
||||
$diffPath = implode(DIRECTORY_SEPARATOR, [$histDir, ($i - 1), "diff.zip"]);
|
||||
if (file_exists($diffPath)) {
|
||||
// write the path to the diff.zip archive with differences in this file version
|
||||
$dataObj["changesUrl"] = getHistoryDownloadUrl($filename, $i - 1, "diff.zip");
|
||||
}
|
||||
}
|
||||
|
||||
$jwtManager = new JwtManager();
|
||||
|
||||
@ -244,23 +244,9 @@ final class DocEditorView extends View
|
||||
// encode the dataSpreadsheet object into the token
|
||||
$dataSpreadsheet["token"] = $jwtManager->jwtEncode($dataSpreadsheet);
|
||||
}
|
||||
$out = getHistory($filename, $filetype, $docKey, $fileuri, $isEnableDirectUrl);
|
||||
$history = $out[0];
|
||||
$historyData = $out[1];
|
||||
|
||||
$historyLayout = "";
|
||||
if ($user->id != "uid-0") {
|
||||
if ($history != null && $historyData != null) {
|
||||
$historyLayout .= " config.events['onRequestHistory'] = function () {
|
||||
// show the document version history
|
||||
docEditor.refreshHistory(".json_encode($history).");};";
|
||||
$historyLayout .= " config.events['onRequestHistoryData'] = function (event) {
|
||||
var ver = event.data;
|
||||
var histData = ".json_encode($historyData).";".
|
||||
"docEditor.setHistoryData(histData[ver - 1]);};
|
||||
config.events['onRequestHistoryClose'] = function () {
|
||||
document.location.reload();
|
||||
};";
|
||||
}
|
||||
$historyLayout .= "// add mentions for not anonymous users
|
||||
config.events['onRequestUsers'] = function (event) {
|
||||
if (event && event.data){
|
||||
|
||||
@ -29,6 +29,7 @@ final class IndexView extends View
|
||||
{
|
||||
parent::__construct($tempName);
|
||||
$formatManager = new FormatManager();
|
||||
$configManager = new ConfigurationManager();
|
||||
|
||||
$storedList = new IndexStoredListView($request);
|
||||
$portalInfo = $this->getPortalInfoStyleDisplay();
|
||||
@ -46,6 +47,7 @@ final class IndexView extends View
|
||||
"fillFormsExtList" => implode(",", $formatManager->fillableExtensions()),
|
||||
"converExtList" => implode(",", $formatManager->convertibleExtensions()),
|
||||
"editedExtList" => implode(",", $formatManager->editableExtensions()),
|
||||
"serverVersion" => $configManager -> getVersion(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
|
||||
var docEditor;
|
||||
var config;
|
||||
let history;
|
||||
|
||||
var innerAlert = function (message, inEditor) {
|
||||
if (console && console.log)
|
||||
@ -218,6 +219,41 @@
|
||||
}
|
||||
};
|
||||
|
||||
function onRequestHistory() {
|
||||
const query = new URLSearchParams(window.location.search)
|
||||
const data = {
|
||||
fileName: query.get('fileID')
|
||||
}
|
||||
const req = new XMLHttpRequest()
|
||||
req.open("POST", 'objhistory')
|
||||
req.setRequestHeader('Content-Type', 'application/json')
|
||||
req.send(JSON.stringify(data))
|
||||
req.onload = function () {
|
||||
if (req.status != 200) {
|
||||
response = JSON.parse(req.response)
|
||||
innerAlert(response.error)
|
||||
return
|
||||
}
|
||||
history = JSON.parse(req.response)
|
||||
docEditor.refreshHistory(
|
||||
{
|
||||
currentVersion: history[0].currentVersion,
|
||||
history: history[0].history
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestHistoryData(event) {
|
||||
var ver = event.data;
|
||||
var histData = history[1]
|
||||
docEditor.setHistoryData(histData[ver - 1])
|
||||
}
|
||||
|
||||
function onRequestHistoryClose() {
|
||||
document.location.reload()
|
||||
}
|
||||
|
||||
function onRequestRestore(event) {
|
||||
const query = new URLSearchParams(window.location.search)
|
||||
const config = {config}
|
||||
@ -235,7 +271,7 @@
|
||||
innerAlert(response.error)
|
||||
return
|
||||
}
|
||||
document.location.reload();
|
||||
onRequestHistory()
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,6 +295,9 @@
|
||||
'onRequestSelectSpreadsheet': onRequestSelectSpreadsheet,
|
||||
'onRequestReferenceData': onRequestReferenceData,
|
||||
'onRequestRestore': onRequestRestore,
|
||||
'onRequestHistoryData': onRequestHistoryData,
|
||||
'onRequestHistory': onRequestHistory,
|
||||
'onRequestHistoryClose': onRequestHistoryClose
|
||||
"onRequestOpen": onRequestOpen,
|
||||
};
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content="{serverVersion}">
|
||||
<title>ONLYOFFICE Document Editors</title>
|
||||
|
||||
<link rel="icon" href="assets/images/favicon.ico" type="image/x-icon" />
|
||||
|
||||
4
web/documentserver-example/python/.flake8
Normal file
4
web/documentserver-example/python/.flake8
Normal file
@ -0,0 +1,4 @@
|
||||
[flake8]
|
||||
max-complexity = 15
|
||||
max-line-length = 120
|
||||
per-file-ignores = __init__.py:F4
|
||||
@ -46,8 +46,11 @@ compose-prod: # Up containers in a production environment.
|
||||
up --detach
|
||||
|
||||
.PHONY: lint
|
||||
lint: # Lint the source code for style and check for types.
|
||||
@flake8
|
||||
lint: # Lint the source code for style.
|
||||
@flake8 --count --show-source --statistics
|
||||
|
||||
.PHONY: types
|
||||
types: # Check the source code for types.
|
||||
@mypy .
|
||||
|
||||
.PHONY: test
|
||||
|
||||
@ -71,6 +71,7 @@ def routers():
|
||||
path('assets', actions.assets),
|
||||
path('download', actions.download),
|
||||
path('downloadhistory', actions.downloadhistory),
|
||||
path('historyobj', actions.history_obj),
|
||||
path('edit', actions.edit),
|
||||
path('files', actions.files),
|
||||
path('reference', actions.reference),
|
||||
|
||||
@ -24,6 +24,9 @@ from src.common import string
|
||||
class ConfigurationManager:
|
||||
version = '1.7.0'
|
||||
|
||||
def getVersion(self) -> str:
|
||||
return self.version
|
||||
|
||||
def example_url(self) -> Optional[ParseResult]:
|
||||
url = environ.get('EXAMPLE_URL')
|
||||
if not url:
|
||||
@ -151,6 +154,7 @@ class ConfigurationManager:
|
||||
'pt-PT': 'Portuguese (Portugal)',
|
||||
'ro': 'Romanian',
|
||||
'ru': 'Russian',
|
||||
'sr-Latn-CS': 'Serbian',
|
||||
'si': 'Sinhala (Sri Lanka)',
|
||||
'sk': 'Slovak',
|
||||
'sl': 'Slovenian',
|
||||
|
||||
@ -214,8 +214,11 @@ def getHistoryObject(storagePath, filename, docKey, docUrl, isEnableDirectUrl, r
|
||||
'url': prev['url']
|
||||
}
|
||||
dataObj['previous'] = prevInfo # write information about previous file version to the data object
|
||||
# write the path to the diff.zip archive with differences in this file version
|
||||
dataObj['changesUrl'] = getPublicHistUri(filename, i - 1, "diff.zip", req)
|
||||
|
||||
diffPath = os.path.sep.join([histDir, str(i - 1), "diff.zip"])
|
||||
if (os.path.exists(diffPath)):
|
||||
# write the path to the diff.zip archive with differences in this file version
|
||||
dataObj['changesUrl'] = getPublicHistUri(filename, i - 1, "diff.zip", req)
|
||||
|
||||
if jwtManager.isEnabled():
|
||||
dataObj['token'] = jwtManager.encode(dataObj)
|
||||
|
||||
@ -187,7 +187,6 @@ def edit(request):
|
||||
|
||||
ext = fileUtils.getFileExt(filename)
|
||||
|
||||
fileUri = docManager.getFileUri(filename, True, request)
|
||||
directUrl = docManager.getDownloadUrl(filename, request, False)
|
||||
docKey = docManager.generateFileKey(filename, request)
|
||||
fileType = fileUtils.getFileType(filename)
|
||||
@ -373,15 +372,8 @@ def edit(request):
|
||||
dataDocument['token'] = jwtManager.encode(dataDocument) # encode the dataDocument object into a token
|
||||
dataSpreadsheet['token'] = jwtManager.encode(dataSpreadsheet) # encode the dataSpreadsheet object into a token
|
||||
|
||||
# get the document history
|
||||
hist = historyManager.getHistoryObject(storagePath, filename, docKey, fileUri, isEnableDirectUrl, request)
|
||||
|
||||
context = { # the data that will be passed to the template
|
||||
'cfg': json.dumps(edConfig), # the document config in json format
|
||||
# the information about the current version
|
||||
'history': json.dumps(hist['history']) if 'history' in hist else None,
|
||||
# the information about the previous document versions if they exist
|
||||
'historyData': json.dumps(hist['historyData']) if 'historyData' in hist else None,
|
||||
'fileType': fileType, # the file type of the document (text, spreadsheet or presentation)
|
||||
'apiUrl': config_manager.document_server_api_url().geturl(), # the absolute URL to the api
|
||||
# the image which will be inserted into the document
|
||||
@ -528,6 +520,27 @@ def downloadhistory(request):
|
||||
return HttpResponse(json.dumps(response), content_type='application/json', status=404)
|
||||
|
||||
|
||||
def history_obj(request):
|
||||
body = json.loads(request.body)
|
||||
response = {}
|
||||
file_name = None
|
||||
|
||||
try:
|
||||
file_name = body['fileName']
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if file_name is None:
|
||||
response.setdefault('error', 'File not found')
|
||||
return HttpResponse(json.dumps(response), content_type='application/json', status=404)
|
||||
|
||||
storage_path = docManager.getStoragePath(file_name, request)
|
||||
doc_key = docManager.generateFileKey(file_name, request)
|
||||
file_url = docManager.getDownloadUrl(file_name, request)
|
||||
response = historyManager.getHistoryObject(storage_path, file_name, doc_key, file_url, False, request)
|
||||
return HttpResponse(json.dumps(response), content_type='application/json')
|
||||
|
||||
|
||||
# referenceData
|
||||
def reference(request):
|
||||
response = {}
|
||||
|
||||
@ -45,7 +45,8 @@ def default(request): # default parameters that will be passed to the template
|
||||
'convExt': json.dumps(format_manager.convertible_extensions()), # file extensions that can be converted
|
||||
'files': docManager.getStoredFiles(request), # information about stored files
|
||||
'fillExt': json.dumps(format_manager.fillable_extensions()),
|
||||
'directUrl': str(getDirectUrlParam(request)).lower
|
||||
'directUrl': str(getDirectUrlParam(request)).lower,
|
||||
'serverVersion': config_manager.getVersion()
|
||||
}
|
||||
# execute the "index.html" template with context data and return http response in json format
|
||||
return render(request, 'index.html', context)
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
|
||||
var docEditor;
|
||||
var config;
|
||||
var hist;
|
||||
|
||||
var innerAlert = function (message, inEditor) {
|
||||
if (console && console.log)
|
||||
@ -224,10 +225,39 @@
|
||||
innerAlert(response.error)
|
||||
return
|
||||
}
|
||||
document.location.reload();
|
||||
onRequestHistory()
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestHistory(){
|
||||
const query = new URLSearchParams(window.location.search)
|
||||
data = {
|
||||
fileName: query.get('filename')
|
||||
}
|
||||
const req = new XMLHttpRequest()
|
||||
req.open("POST", '/historyobj')
|
||||
req.send(JSON.stringify(data))
|
||||
req.onload = function () {
|
||||
if (req.status != 200) {
|
||||
response = JSON.parse(req.response)
|
||||
innerAlert(response.error)
|
||||
return
|
||||
}
|
||||
hist = JSON.parse(req.response)
|
||||
docEditor.refreshHistory(hist.history)
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestHistoryData(event) {
|
||||
var ver = event.data;
|
||||
var histData = hist.historyData;
|
||||
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
|
||||
}
|
||||
|
||||
function onRequestHistoryClose(){
|
||||
document.location.reload();
|
||||
}
|
||||
|
||||
var connectEditor = function () {
|
||||
|
||||
config = {{ cfg | safe }}
|
||||
@ -243,32 +273,16 @@
|
||||
'onRequestInsertImage': onRequestInsertImage,
|
||||
'onRequestSelectDocument': onRequestSelectDocument,
|
||||
"onRequestSelectSpreadsheet": onRequestSelectSpreadsheet,
|
||||
'onRequestRestore': onRequestRestore
|
||||
'onRequestRestore': onRequestRestore,
|
||||
'onRequestHistory': onRequestHistory,
|
||||
'onRequestHistoryData': onRequestHistoryData,
|
||||
'onRequestHistoryClose': onRequestHistoryClose
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (config.editorConfig.user.id) {
|
||||
|
||||
{% if history and historyData %}
|
||||
|
||||
// the user is trying to show the document version history
|
||||
config.events['onRequestHistory'] = function () {
|
||||
docEditor.refreshHistory({{ history | safe }}); // show the document version history
|
||||
};
|
||||
// the user is trying to click the specific document version in the document version history
|
||||
config.events['onRequestHistoryData'] = function (event) {
|
||||
var ver = event.data;
|
||||
var histData = {{ historyData | safe }};
|
||||
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
|
||||
};
|
||||
// the user is trying to go back to the document from viewing the document version history
|
||||
config.events['onRequestHistoryClose'] = function () {
|
||||
document.location.reload();
|
||||
};
|
||||
|
||||
{% endif %}
|
||||
|
||||
// add mentions for not anonymous users
|
||||
config.events['onRequestUsers'] = function (event) {
|
||||
if (event && event.data){
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="server-version" content="{{serverVersion}}">
|
||||
<title>ONLYOFFICE Document Editors</title>
|
||||
<link href="{% static "images/favicon.ico" %}" rel="shortcut icon" type="image/x-icon" />
|
||||
<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:900,800,700,600,500,400,300&subset=latin,cyrillic-ext,cyrillic,latin-ext" />
|
||||
|
||||
163
web/documentserver-example/ruby/.rubocop.yml
Normal file
163
web/documentserver-example/ruby/.rubocop.yml
Normal file
@ -0,0 +1,163 @@
|
||||
require: rubocop-rails
|
||||
|
||||
AllCops:
|
||||
NewCops: enable
|
||||
|
||||
# Bundler
|
||||
|
||||
Bundler/GemVersion:
|
||||
Enabled: true
|
||||
EnforcedStyle: required
|
||||
|
||||
# Layout
|
||||
|
||||
Layout/EmptyComment:
|
||||
Enabled: true
|
||||
AllowBorderComment: false
|
||||
AllowMarginComment: true
|
||||
|
||||
Layout/EmptyLineAfterGuardClause:
|
||||
Enabled: false
|
||||
|
||||
Layout/EndOfLine:
|
||||
Enabled: true
|
||||
EnforcedStyle: lf
|
||||
|
||||
Layout/FirstArrayElementLineBreak:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/FirstHashElementLineBreak:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/FirstMethodArgumentLineBreak:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/FirstMethodParameterLineBreak:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/LineLength:
|
||||
Enabled: true
|
||||
Max: 120
|
||||
|
||||
Layout/MultilineArrayLineBreaks:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/MultilineAssignmentLayout:
|
||||
Enabled: true
|
||||
EnforcedStyle: new_line
|
||||
SupportedTypes: []
|
||||
|
||||
Layout/MultilineHashKeyLineBreaks:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/MultilineMethodArgumentLineBreaks:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/MultilineMethodParameterLineBreaks:
|
||||
Enabled: true
|
||||
AllowMultilineFinalElement: false
|
||||
|
||||
Layout/SingleLineBlockChain:
|
||||
Enabled: true
|
||||
|
||||
# Lint
|
||||
|
||||
Lint/NumberConversion:
|
||||
Enabled: true
|
||||
|
||||
Lint/DuplicateBranch:
|
||||
Enabled: false
|
||||
|
||||
# Metrics
|
||||
|
||||
Metrics:
|
||||
Enabled: false
|
||||
|
||||
# Naming
|
||||
|
||||
Naming/InclusiveLanguage:
|
||||
Enabled: true
|
||||
|
||||
# Style
|
||||
|
||||
Style/AccessModifierDeclarations:
|
||||
Enabled: true
|
||||
EnforcedStyle: inline
|
||||
|
||||
Style/AccessorGrouping:
|
||||
Enabled: true
|
||||
EnforcedStyle: separated
|
||||
|
||||
Style/ArrayCoercion:
|
||||
Enabled: true
|
||||
|
||||
Style/ClassAndModuleChildren:
|
||||
Enabled: true
|
||||
EnforcedStyle: compact
|
||||
|
||||
Style/ClassMethodsDefinitions:
|
||||
Enabled: true
|
||||
|
||||
Style/CollectionMethods:
|
||||
Enabled: true
|
||||
|
||||
Style/DateTime:
|
||||
Enabled: true
|
||||
|
||||
Style/EndlessMethod:
|
||||
Enabled: true
|
||||
EnforcedStyle: disallow
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: true
|
||||
EnforcedStyle: always
|
||||
Exclude:
|
||||
- "Gemfile"
|
||||
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
|
||||
Style/Lambda:
|
||||
Enabled: true
|
||||
EnforcedStyle: lambda
|
||||
|
||||
Style/MethodCallWithArgsParentheses:
|
||||
Enabled: true
|
||||
AllowedMethods: []
|
||||
AllowedPatterns: []
|
||||
|
||||
Style/MethodCalledOnDoEndBlock:
|
||||
Enabled: true
|
||||
|
||||
Style/MissingElse:
|
||||
Enabled: true
|
||||
EnforcedStyle: case
|
||||
|
||||
Style/MultipleComparison:
|
||||
Enabled: false
|
||||
|
||||
Style/NumberedParameters:
|
||||
Enabled: true
|
||||
EnforcedStyle: disallow
|
||||
|
||||
Style/ParenthesesAroundCondition:
|
||||
Enabled: true
|
||||
AllowInMultilineConditions: true
|
||||
|
||||
Style/StringHashKeys:
|
||||
Enabled: true
|
||||
|
||||
Style/SymbolArray:
|
||||
Enabled: true
|
||||
EnforcedStyle: brackets
|
||||
|
||||
Style/WordArray:
|
||||
Enabled: true
|
||||
EnforcedStyle: brackets
|
||||
@ -1,25 +1,28 @@
|
||||
source "https://rubygems.org"
|
||||
# frozen_string_literal: true
|
||||
|
||||
gem "byebug", "~> 11.1", :groups => [:development, :test]
|
||||
gem "coffee-rails", "~> 5.0"
|
||||
gem "dalli", "~> 3.2", :group => :development
|
||||
gem "jbuilder", "~> 2.11"
|
||||
gem "jquery-rails", "~> 4.5"
|
||||
gem "jwt", "~> 2.7"
|
||||
gem "mimemagic", github: "mimemagicrb/mimemagic", ref: "01f92d86d15d85cfd0f20dabd025dcbd36a8a60f"
|
||||
gem "rack-cors", "~> 2.0"
|
||||
gem "rails", "~> 7.0.8"
|
||||
gem "rubocop", "~> 1.52", :group => :development
|
||||
gem "sass-rails", "~> 6.0"
|
||||
gem "sdoc", "~> 2.6", :group => :doc
|
||||
gem "sorbet-runtime", "~> 0.5.10871"
|
||||
gem "test-unit", "~> 3.6", :groups => [:development, :test]
|
||||
gem "turbolinks", "~> 5.2"
|
||||
gem "tzinfo-data", "~> 1.2023"
|
||||
gem "uglifier", "~> 4.2"
|
||||
gem "uuid", "~> 2.3"
|
||||
gem "web-console", "~> 4.2", :groups => [:development, :test]
|
||||
gem "webrick", "~> 1.8"
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'byebug', '~> 11.1', groups: [:development, :test]
|
||||
gem 'coffee-rails', '~> 5.0'
|
||||
gem 'dalli', '~> 3.2', group: :development
|
||||
gem 'jbuilder', '~> 2.11'
|
||||
gem 'jquery-rails', '~> 4.5'
|
||||
gem 'jwt', '~> 2.7'
|
||||
gem 'mimemagic', github: 'mimemagicrb/mimemagic', ref: '01f92d86d15d85cfd0f20dabd025dcbd36a8a60f'
|
||||
gem 'rack-cors', '~> 2.0'
|
||||
gem 'rails', '~> 7.0.8'
|
||||
gem 'rubocop', '~> 1.52', group: :development
|
||||
gem 'rubocop-rails', '~> 2.20', group: :development
|
||||
gem 'sass-rails', '~> 6.0'
|
||||
gem 'sdoc', '~> 2.6', group: :doc
|
||||
gem 'sorbet-runtime', '~> 0.5.10871'
|
||||
gem 'test-unit', '~> 3.6', groups: [:development, :test]
|
||||
gem 'turbolinks', '~> 5.2'
|
||||
gem 'tzinfo-data', '~> 1.2023'
|
||||
gem 'uglifier', '~> 4.2'
|
||||
gem 'uuid', '~> 2.3'
|
||||
gem 'web-console', '~> 4.2', groups: [:development, :test]
|
||||
gem 'webrick', '~> 1.8'
|
||||
|
||||
# Unfortunately, Sorbet only supports Darwin and Linux-based systems.
|
||||
# Additionally, it doesn't support Linux on ARM64, which may be used in a Docker
|
||||
@ -27,7 +30,7 @@ gem "webrick", "~> 1.8"
|
||||
#
|
||||
# https://github.com/sorbet/sorbet/issues/4011
|
||||
# https://github.com/sorbet/sorbet/issues/4119
|
||||
install_if -> { RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /x86_64/ } do
|
||||
gem "sorbet", "~> 0.5.10871", :group => :development
|
||||
gem "tapioca", "~> 0.11.6", :group => :development
|
||||
install_if lambda { RUBY_PLATFORM =~ /darwin/ || RUBY_PLATFORM =~ /x86_64/ } do
|
||||
gem 'sorbet', '~> 0.5.10871', group: :development
|
||||
gem 'tapioca', '~> 0.11.6', group: :development
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rake/testtask'
|
||||
require_relative 'config/application'
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ require 'pathname'
|
||||
require 'sorbet-runtime'
|
||||
require 'uri'
|
||||
|
||||
# ConfigurationManager manages configuration settings for the application.
|
||||
class ConfigurationManager
|
||||
extend T::Sig
|
||||
|
||||
@ -35,8 +36,9 @@ class ConfigurationManager
|
||||
|
||||
sig { returns(T.nilable(URI::Generic)) }
|
||||
def example_uri
|
||||
url = ENV['EXAMPLE_URL']
|
||||
url = ENV.fetch('EXAMPLE_URL', nil)
|
||||
return nil if url.nil?
|
||||
|
||||
URI(url)
|
||||
end
|
||||
|
||||
@ -48,8 +50,9 @@ class ConfigurationManager
|
||||
|
||||
sig { returns(URI::Generic) }
|
||||
def document_server_private_uri
|
||||
url = ENV['DOCUMENT_SERVER_PRIVATE_URL']
|
||||
url = ENV.fetch('DOCUMENT_SERVER_PRIVATE_URL', nil)
|
||||
return URI(url) if url
|
||||
|
||||
document_server_public_uri
|
||||
end
|
||||
|
||||
@ -97,15 +100,17 @@ class ConfigurationManager
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def jwt_use_for_request
|
||||
env = ENV['JWT_USE_FOR_REQUEST']
|
||||
env = ENV.fetch('JWT_USE_FOR_REQUEST', nil)
|
||||
return ActiveModel::Type::Boolean.new.cast(env) if env
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def ssl_verify_peer_mode_enabled
|
||||
env = ENV['SSL_VERIFY_PEER_MODE_ENABLED']
|
||||
env = ENV.fetch('SSL_VERIFY_PEER_MODE_ENABLED', nil)
|
||||
return ActiveModel::Type::Boolean.new.cast(env) if env
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
@ -114,6 +119,7 @@ class ConfigurationManager
|
||||
storage_path = ENV['STORAGE_PATH'] || 'storage'
|
||||
storage_directory = Pathname(storage_path)
|
||||
return storage_directory if storage_directory.absolute?
|
||||
|
||||
current_directory = Pathname(File.expand_path(__dir__))
|
||||
directory = current_directory.join('..', '..', storage_directory)
|
||||
directory.cleanpath
|
||||
@ -121,8 +127,9 @@ class ConfigurationManager
|
||||
|
||||
sig { returns(Numeric) }
|
||||
def maximum_file_size
|
||||
env = ENV['MAXIMUM_FILE_SIZE']
|
||||
return env.to_i if env
|
||||
env = ENV.fetch('MAXIMUM_FILE_SIZE', nil)
|
||||
return Integer(env, 10) if env
|
||||
|
||||
5 * 1024 * 1024
|
||||
end
|
||||
|
||||
@ -134,46 +141,47 @@ class ConfigurationManager
|
||||
sig { returns(T::Hash[String, String]) }
|
||||
def languages
|
||||
{
|
||||
'en' => 'English',
|
||||
'hy' => 'Armenian',
|
||||
'az' => 'Azerbaijani',
|
||||
'eu' => 'Basque',
|
||||
'be' => 'Belarusian',
|
||||
'bg' => 'Bulgarian',
|
||||
'ca' => 'Catalan',
|
||||
'zh' => 'Chinese (Simplified)',
|
||||
'zh-TW' => 'Chinese (Traditional)',
|
||||
'cs' => 'Czech',
|
||||
'da' => 'Danish',
|
||||
'nl' => 'Dutch',
|
||||
'fi' => 'Finnish',
|
||||
'fr' => 'French',
|
||||
'gl' => 'Galego',
|
||||
'de' => 'German',
|
||||
'el' => 'Greek',
|
||||
'hu' => 'Hungarian',
|
||||
'id' => 'Indonesian',
|
||||
'it' => 'Italian',
|
||||
'ja' => 'Japanese',
|
||||
'ko' => 'Korean',
|
||||
'lo' => 'Lao',
|
||||
'lv' => 'Latvian',
|
||||
'ms' => 'Malay (Malaysia)',
|
||||
'no' => 'Norwegian',
|
||||
'pl' => 'Polish',
|
||||
'pt' => 'Portuguese (Brazil)',
|
||||
'pt-PT' => 'Portuguese (Portugal)',
|
||||
'ro' => 'Romanian',
|
||||
'ru' => 'Russian',
|
||||
'si' => 'Sinhala (Sri Lanka)',
|
||||
'sk' => 'Slovak',
|
||||
'sl' => 'Slovenian',
|
||||
'es' => 'Spanish',
|
||||
'sv' => 'Swedish',
|
||||
'tr' => 'Turkish',
|
||||
'uk' => 'Ukrainian',
|
||||
'vi' => 'Vietnamese',
|
||||
'aa-AA' => 'Test Language'
|
||||
en: 'English',
|
||||
hy: 'Armenian',
|
||||
az: 'Azerbaijani',
|
||||
eu: 'Basque',
|
||||
be: 'Belarusian',
|
||||
bg: 'Bulgarian',
|
||||
ca: 'Catalan',
|
||||
zh: 'Chinese (Simplified)',
|
||||
'zh-TW': 'Chinese (Traditional)',
|
||||
cs: 'Czech',
|
||||
da: 'Danish',
|
||||
nl: 'Dutch',
|
||||
fi: 'Finnish',
|
||||
fr: 'French',
|
||||
gl: 'Galego',
|
||||
de: 'German',
|
||||
el: 'Greek',
|
||||
hu: 'Hungarian',
|
||||
id: 'Indonesian',
|
||||
it: 'Italian',
|
||||
ja: 'Japanese',
|
||||
ko: 'Korean',
|
||||
lo: 'Lao',
|
||||
lv: 'Latvian',
|
||||
ms: 'Malay (Malaysia)',
|
||||
no: 'Norwegian',
|
||||
pl: 'Polish',
|
||||
pt: 'Portuguese (Brazil)',
|
||||
'pt-PT': 'Portuguese (Portugal)',
|
||||
ro: 'Romanian',
|
||||
ru: 'Russian',
|
||||
'sr-Latn-CS': 'Serbian',
|
||||
si: 'Sinhala (Sri Lanka)',
|
||||
sk: 'Slovak',
|
||||
sl: 'Slovenian',
|
||||
es: 'Spanish',
|
||||
sv: 'Swedish',
|
||||
tr: 'Turkish',
|
||||
uk: 'Ukrainian',
|
||||
vi: 'Vietnamese',
|
||||
'aa-AA': 'Test Language'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
require 'test/unit'
|
||||
require_relative 'configuration'
|
||||
|
||||
# Enviroment module provides a mechanism for capturing and restoring the environment.
|
||||
module Enviroment
|
||||
def initialize(name)
|
||||
@env = ENV.to_hash
|
||||
@ -27,10 +28,11 @@ module Enviroment
|
||||
end
|
||||
|
||||
def setup
|
||||
ENV.replace @env
|
||||
ENV.replace(@env)
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the ConfigurationManager class.
|
||||
class ConfigurationManagerTests < Test::Unit::TestCase
|
||||
def test_corresponds_the_latest_version
|
||||
config_manager = ConfigurationManager.new
|
||||
@ -38,6 +40,7 @@ class ConfigurationManagerTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the example_uri method of ConfigurationManager.
|
||||
class ConfigurationManagerExampleURITests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -55,6 +58,7 @@ class ConfigurationManagerExampleURITests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the document_server_public_uri method of ConfigurationManager.
|
||||
class ConfigurationManagerDocumentServerPublicURITests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -72,6 +76,7 @@ class ConfigurationManagerDocumentServerPublicURITests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the document_server_private_uri method of ConfigurationManager.
|
||||
class ConfigurationManagerDocumentServerPrivateURITests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -89,6 +94,7 @@ class ConfigurationManagerDocumentServerPrivateURITests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the document_server_api_uri method of ConfigurationManager.
|
||||
class ConfigurationManagerDocumentServerAPIURITests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -112,6 +118,7 @@ class ConfigurationManagerDocumentServerAPIURITests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the document_server_preloader_uri method of ConfigurationManager.
|
||||
class ConfigurationManagerDocumentServerPreloaderURITests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -135,6 +142,7 @@ class ConfigurationManagerDocumentServerPreloaderURITests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the document_server_command_uri method of ConfigurationManager.
|
||||
class ConfigurationManagerDocumentServerCommandURITests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -158,6 +166,7 @@ class ConfigurationManagerDocumentServerCommandURITests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the document_server_converter_uri method of ConfigurationManager.
|
||||
class ConfigurationManagerDocumentServerConverterURITests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -181,6 +190,7 @@ class ConfigurationManagerDocumentServerConverterURITests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the jwt_secret method of ConfigurationManager.
|
||||
class ConfigurationManagerJWTSecretTests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -198,6 +208,7 @@ class ConfigurationManagerJWTSecretTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the jwt_header method of ConfigurationManager.
|
||||
class ConfigurationManagerJWTHeaderTests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -215,6 +226,7 @@ class ConfigurationManagerJWTHeaderTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the jwt_use_for_request method of ConfigurationManager.
|
||||
class ConfigurationManagerJWTUseForRequest < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -232,6 +244,7 @@ class ConfigurationManagerJWTUseForRequest < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the ssl_verify_peer_mode_enabled method of ConfigurationManager.
|
||||
class ConfigurationManagerSSLTests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -249,6 +262,7 @@ class ConfigurationManagerSSLTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the storage_path method of ConfigurationManager.
|
||||
class ConfigurationManagerStoragePathTests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -275,6 +289,7 @@ class ConfigurationManagerStoragePathTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the maximum_file_size method of ConfigurationManager.
|
||||
class ConfigurationManagerMaximumFileSizeTests < Test::Unit::TestCase
|
||||
include Enviroment
|
||||
|
||||
@ -292,6 +307,7 @@ class ConfigurationManagerMaximumFileSizeTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# For testing the convertation_timeout method of ConfigurationManager.
|
||||
class ConfigurationManagerConversionTimeoutTests < Test::Unit::TestCase
|
||||
def test_assigns_a_default_value
|
||||
config_manager = ConfigurationManager.new
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -15,4 +17,4 @@
|
||||
#
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -19,6 +21,7 @@ require 'net/http'
|
||||
require 'mimemagic'
|
||||
require_relative '../configuration/configuration'
|
||||
|
||||
# Handling requests controller
|
||||
class HomeController < ApplicationController
|
||||
@config_manager = ConfigurationManager.new
|
||||
|
||||
@ -26,30 +29,33 @@ class HomeController < ApplicationController
|
||||
attr_reader :config_manager
|
||||
end
|
||||
|
||||
def index
|
||||
end
|
||||
def index; end
|
||||
|
||||
def editor
|
||||
|
||||
DocumentHelper.init(request.remote_ip, request.base_url)
|
||||
user = Users.get_user(params[:userId])
|
||||
@file = FileModel.new(:file_name => File.basename(params[:fileName]), :mode => params[:editorsMode], :type => params[:editorsType], :user_ip => request.remote_ip, :lang => cookies[:ulang], :user => user, :action_data => params[:actionLink], :direct_url => params[:directUrl])
|
||||
|
||||
@file = FileModel.new(
|
||||
file_name: File.basename(params[:fileName]),
|
||||
mode: params[:editorsMode],
|
||||
type: params[:editorsType],
|
||||
user_ip: request.remote_ip,
|
||||
lang: cookies[:ulang],
|
||||
user:,
|
||||
action_data: params[:actionLink],
|
||||
direct_url: params[:directUrl]
|
||||
)
|
||||
end
|
||||
|
||||
# creating a sample document
|
||||
def sample
|
||||
|
||||
DocumentHelper.init(request.remote_ip, request.base_url)
|
||||
user = Users.get_user(params[:userId])
|
||||
file_name = DocumentHelper.create_demo(params[:fileExt], params[:sample], user)
|
||||
redirect_to :controller => 'home', :action => 'editor', :fileName => file_name, :userId => user.id
|
||||
|
||||
redirect_to(controller: 'home', action: 'editor', fileName: file_name, userId: user.id)
|
||||
end
|
||||
|
||||
# uploading a file
|
||||
def upload
|
||||
|
||||
DocumentHelper.init(request.remote_ip, request.base_url)
|
||||
|
||||
begin
|
||||
@ -58,187 +64,196 @@ class HomeController < ApplicationController
|
||||
cur_size = http_posted_file.size
|
||||
|
||||
# check if the file size exceeds the maximum file size
|
||||
if DocumentHelper.file_size_max < cur_size || cur_size <= 0
|
||||
raise 'File size is incorrect'
|
||||
end
|
||||
raise('File size is incorrect') if DocumentHelper.file_size_max < cur_size || cur_size <= 0
|
||||
|
||||
cur_ext = File.extname(file_name).downcase
|
||||
|
||||
# check if the file extension is supported by the editor
|
||||
unless DocumentHelper.file_exts.include? cur_ext
|
||||
raise 'File type is not supported'
|
||||
end
|
||||
raise('File type is not supported') unless DocumentHelper.file_exts.include?(cur_ext)
|
||||
|
||||
# get the correct file name if such a name already exists
|
||||
file_name = DocumentHelper.get_correct_name(file_name, nil)
|
||||
document_type = FileUtility.get_file_type(file_name)
|
||||
|
||||
# write the uploaded file to the storage directory
|
||||
File.open(DocumentHelper.storage_path(file_name, nil), 'wb') do |file|
|
||||
file.write(http_posted_file.read)
|
||||
end
|
||||
File.binwrite(DocumentHelper.storage_path(file_name, nil), http_posted_file.read)
|
||||
|
||||
# create file meta information
|
||||
user = Users.get_user(params[:userId])
|
||||
|
||||
DocumentHelper.create_meta(file_name, user.id, user.name, nil)
|
||||
|
||||
render plain: '{ "filename": "' + file_name + '", "documentType": "' + document_type + '"}' # write a new file name to the response
|
||||
rescue => ex
|
||||
render plain: '{ "error": "' + ex.message + '"}' # write an error message to the response
|
||||
# write a new file name to the response
|
||||
render(plain: "{ \"filename\": \"#{file_name}\", \"documentType\": \"#{document_type}\"}")
|
||||
rescue StandardError => e
|
||||
render(plain: "{ \"error\": \"#{e.message}\"}") # write an error message to the response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# converting a file
|
||||
def convert
|
||||
file_data = request.body.read
|
||||
return '' if file_data.blank?
|
||||
|
||||
begin
|
||||
file_data = request.body.read
|
||||
if file_data == nil || file_data.empty?
|
||||
return ""
|
||||
body = JSON.parse(file_data)
|
||||
|
||||
file_name = File.basename(body['filename'])
|
||||
lang = cookies[:ulang] || 'en'
|
||||
file_pass = body['filePass'] || nil
|
||||
file_uri = DocumentHelper.get_download_url(file_name)
|
||||
extension = File.extname(file_name).downcase
|
||||
internal_extension = 'ooxml'
|
||||
|
||||
if DocumentHelper.convert_exts.include?(extension) # check if the file with such an extension can be converted
|
||||
key = ServiceConverter.generate_revision_id(file_uri) # generate document key
|
||||
percent, new_file_uri, new_file_type = ServiceConverter.get_converted_data(
|
||||
file_uri,
|
||||
extension.delete('.'),
|
||||
internal_extension.delete('.'),
|
||||
key,
|
||||
true,
|
||||
file_pass,
|
||||
lang
|
||||
) # get the url and file type of the converted file and the conversion percentage
|
||||
|
||||
# if the conversion isn't completed, write file name and step values to the response
|
||||
if percent != 100
|
||||
render(plain: "{ \"step\" : \"#{percent}\", \"filename\" : \"#{file_name}\"}")
|
||||
return
|
||||
end
|
||||
|
||||
body = JSON.parse(file_data)
|
||||
|
||||
file_name = File.basename(body["filename"])
|
||||
lang = cookies[:ulang] ? cookies[:ulang] : "en"
|
||||
file_pass = body["filePass"] ? body["filePass"] : nil
|
||||
file_uri = DocumentHelper.get_download_url(file_name)
|
||||
extension = File.extname(file_name).downcase
|
||||
internal_extension = 'ooxml'
|
||||
# get the correct file name if such a name already exists
|
||||
correct_name = DocumentHelper.get_correct_name("#{File.basename(file_name, extension)}.#{new_file_type}", nil)
|
||||
|
||||
if DocumentHelper.convert_exts.include? (extension) # check if the file with such an extension can be converted
|
||||
key = ServiceConverter.generate_revision_id(file_uri) # generate document key
|
||||
percent, new_file_uri, new_file_type = ServiceConverter.get_converted_data(file_uri, extension.delete('.'), internal_extension.delete('.'), key, true, file_pass, lang) # get the url and file type of the converted file and the conversion percentage
|
||||
uri = URI.parse(new_file_uri) # create the request url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
|
||||
# if the conversion isn't completed, write file name and step values to the response
|
||||
if percent != 100
|
||||
render plain: '{ "step" : "' + percent.to_s + '", "filename" : "' + file_name + '"}'
|
||||
return
|
||||
end
|
||||
DocumentHelper.verify_ssl(new_file_uri, http)
|
||||
|
||||
# get the correct file name if such a name already exists
|
||||
correct_name = DocumentHelper.get_correct_name(File.basename(file_name, extension) + "." + new_file_type, nil)
|
||||
req = Net::HTTP::Get.new(uri.request_uri) # create the get requets
|
||||
res = http.request(req)
|
||||
data = res.body
|
||||
|
||||
uri = URI.parse(new_file_uri) # create the request url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
raise('stream is null') if data.nil?
|
||||
|
||||
DocumentHelper.verify_ssl(new_file_uri, http)
|
||||
# write a file with a new extension, but with the content from the origin file
|
||||
File.binwrite(DocumentHelper.storage_path(correct_name, nil), data)
|
||||
|
||||
req = Net::HTTP::Get.new(uri.request_uri) # create the get requets
|
||||
res = http.request(req)
|
||||
data = res.body
|
||||
old_storage_path = DocumentHelper.storage_path(file_name, nil)
|
||||
FileUtils.rm_f(old_storage_path)
|
||||
|
||||
if data == nil
|
||||
raise 'stream is null'
|
||||
end
|
||||
file_name = correct_name
|
||||
user = Users.get_user(params[:userId])
|
||||
|
||||
# write a file with a new extension, but with the content from the origin file
|
||||
File.open(DocumentHelper.storage_path(correct_name, nil), 'wb') do |file|
|
||||
file.write(data)
|
||||
end
|
||||
|
||||
old_storage_path = DocumentHelper.storage_path(file_name, nil)
|
||||
if File.exist?(old_storage_path)
|
||||
File.delete(old_storage_path)
|
||||
end
|
||||
|
||||
file_name = correct_name
|
||||
user = Users.get_user(params[:userId])
|
||||
|
||||
DocumentHelper.create_meta(file_name, user.id, user.name, nil) # create meta data of the new file
|
||||
end
|
||||
|
||||
render plain: '{ "filename" : "' + file_name + '"}'
|
||||
rescue => ex
|
||||
render plain: '{ "error": "' + ex.message + '"}'
|
||||
DocumentHelper.create_meta(file_name, user.id, user.name, nil) # create meta data of the new file
|
||||
end
|
||||
|
||||
render(plain: "{ \"filename\" : \"#{file_name}\"}")
|
||||
rescue StandardError => e
|
||||
render(plain: "{ \"error\": \"#{e.message}\"}")
|
||||
end
|
||||
|
||||
def historyobj
|
||||
data = request.body.read
|
||||
if data.blank?
|
||||
return ''
|
||||
end
|
||||
file_data = JSON.parse(data)
|
||||
file = FileModel.new(
|
||||
file_name: File.basename(file_data['file_name']),
|
||||
mode: file_data['mode'],
|
||||
type: file_data['type'],
|
||||
user_ip: file_data['user_ip'],
|
||||
lang: file_data['lang'],
|
||||
user: file_data['user'],
|
||||
action_data: file_data['action_data'],
|
||||
direct_url: file_data['direct_url']
|
||||
)
|
||||
history = file.get_history
|
||||
render(json: history)
|
||||
rescue StandardError
|
||||
render(json: '{ "error": "File not found"}')
|
||||
end
|
||||
|
||||
# downloading a history file from public
|
||||
def downloadhistory
|
||||
begin
|
||||
file_name = File.basename(params[:fileName])
|
||||
user_address = params[:userAddress]
|
||||
version = params[:ver]
|
||||
file = params[:file]
|
||||
isEmbedded = params[:dmode]
|
||||
file_name = File.basename(params[:fileName])
|
||||
user_address = params[:userAddress]
|
||||
version = params[:ver]
|
||||
file = params[:file]
|
||||
params[:dmode]
|
||||
|
||||
if JwtHelper.is_enabled && JwtHelper.use_for_request
|
||||
jwtHeader = HomeController.config_manager.jwt_header;
|
||||
if request.headers[jwtHeader]
|
||||
hdr = request.headers[jwtHeader]
|
||||
hdr.slice!(0, "Bearer ".length)
|
||||
token = JwtHelper.decode(hdr)
|
||||
if !token || token.eql?("")
|
||||
render plain: "JWT validation failed", :status => 403
|
||||
return
|
||||
end
|
||||
else
|
||||
render plain: "JWT validation failed", :status => 403
|
||||
if JwtHelper.enabled? && JwtHelper.use_for_request
|
||||
jwt_header = HomeController.config_manager.jwt_header
|
||||
if request.headers[jwt_header]
|
||||
hdr = request.headers[jwt_header]
|
||||
hdr.slice!(0, 'Bearer '.length)
|
||||
token = JwtHelper.decode(hdr)
|
||||
if !token || token.eql?('')
|
||||
render(plain: 'JWT validation failed', status: :forbidden)
|
||||
return
|
||||
end
|
||||
else
|
||||
render(plain: 'JWT validation failed', status: :forbidden)
|
||||
return
|
||||
end
|
||||
hist_path = DocumentHelper.storage_path(file_name, user_address) + "-hist" # or to the original document
|
||||
|
||||
file_path = File.join(hist_path, version, file)
|
||||
|
||||
# add headers to the response to specify the page parameters
|
||||
response.headers['Content-Length'] = File.size(file_path).to_s
|
||||
response.headers['Content-Type'] = MimeMagic.by_path(file_path).eql?(nil) ? nil : MimeMagic.by_path(file_path).type
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8\'\'" + ERB::Util.url_encode(file)
|
||||
|
||||
send_file file_path, :x_sendfile => true
|
||||
rescue => ex
|
||||
render plain: '{ "error": "File not found"}'
|
||||
end
|
||||
hist_path = "#{DocumentHelper.storage_path(file_name, user_address)}-hist" # or to the original document
|
||||
|
||||
file_path = File.join(hist_path, version, file)
|
||||
|
||||
# add headers to the response to specify the page parameters
|
||||
response.headers['Content-Length'] = File.size(file_path).to_s
|
||||
response.headers['Content-Type'] =
|
||||
MimeMagic.by_path(file_path).eql?(nil) ? nil : MimeMagic.by_path(file_path).type
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8''#{ERB::Util.url_encode(file)}"
|
||||
|
||||
send_file(file_path, x_sendfile: true)
|
||||
rescue StandardError
|
||||
render(plain: '{ "error": "File not found"}')
|
||||
end
|
||||
|
||||
# tracking file changes
|
||||
def track
|
||||
file_data = TrackHelper.read_body(request) # read the request body
|
||||
if file_data == nil || file_data.empty?
|
||||
render plain: '{"error":1}' # an error occurs if the file is empty
|
||||
file_data = TrackHelper.read_body(request) # read the request body
|
||||
if file_data.blank?
|
||||
render(plain: '{"error":1}') # an error occurs if the file is empty
|
||||
return
|
||||
end
|
||||
|
||||
status = file_data['status'].to_i
|
||||
status = file_data['status']
|
||||
|
||||
user_address = params[:userAddress]
|
||||
file_name = File.basename(params[:fileName])
|
||||
|
||||
if status == 1 # editing
|
||||
if file_data['actions'][0]['type'] == 0 # finished edit
|
||||
user = file_data['actions'][0]['userid'] # get the user id
|
||||
if !file_data['users'].index(user)
|
||||
json_data = TrackHelper.command_request("forcesave", file_data['key']) # call the forcesave command
|
||||
end
|
||||
if status == 1 && (file_data['actions'][0]['type']).zero? # finished edit
|
||||
user = file_data['actions'][0]['userid'] # get the user id
|
||||
unless file_data['users'].index(user)
|
||||
TrackHelper.command_request('forcesave', file_data['key']) # call the forcesave command
|
||||
end
|
||||
end
|
||||
|
||||
if status == 2 || status == 3 # MustSave, Corrupted
|
||||
saved = TrackHelper.process_save(file_data, file_name, user_address) # save file
|
||||
render plain: '{"error":' + saved.to_s + '}'
|
||||
if [2, 3].include?(status) # MustSave, Corrupted
|
||||
saved = TrackHelper.process_save(file_data, file_name, user_address) # save file
|
||||
render(plain: "{\"error\":#{saved}}")
|
||||
return
|
||||
end
|
||||
|
||||
if status == 6 || status == 7 # MustForceave, CorruptedForcesave
|
||||
saved = TrackHelper.process_force_save(file_data, file_name, user_address) # force save file
|
||||
render plain: '{"error":' + saved.to_s + '}'
|
||||
if [6, 7].include?(status) # MustForceave, CorruptedForcesave
|
||||
saved = TrackHelper.process_force_save(file_data, file_name, user_address) # force save file
|
||||
render(plain: "{\"error\":#{saved}}")
|
||||
return
|
||||
end
|
||||
|
||||
render plain: '{"error":0}'
|
||||
return
|
||||
render(plain: '{"error":0}')
|
||||
nil
|
||||
end
|
||||
|
||||
# removing a file
|
||||
def remove
|
||||
file_name = File.basename(params[:filename]) # get the file name
|
||||
if !file_name # if it doesn't exist
|
||||
render plain: '{"success":false}' # report that the operation is unsuccessful
|
||||
file_name = File.basename(params[:filename]) # get the file name
|
||||
unless file_name # if it doesn't exist
|
||||
render(plain: '{"success":false}') # report that the operation is unsuccessful
|
||||
return
|
||||
end
|
||||
|
||||
@ -246,36 +261,34 @@ class HomeController < ApplicationController
|
||||
storage_path = DocumentHelper.storage_path(file_name, nil)
|
||||
hist_dir = DocumentHelper.history_dir(storage_path)
|
||||
|
||||
if File.exist?(storage_path) # if the file exists
|
||||
File.delete(storage_path) # delete it from the storage path
|
||||
end
|
||||
# if the file exists
|
||||
FileUtils.rm_f(storage_path) # delete it from the storage path
|
||||
|
||||
if Dir.exist?(hist_dir) # if the history directory of this file exists
|
||||
FileUtils.remove_entry_secure(hist_dir) # delete it
|
||||
end
|
||||
# if the history directory of this file exists
|
||||
FileUtils.rm_rf(hist_dir) # delete it
|
||||
|
||||
render plain: '{"success":true}' # report that the operation is successful
|
||||
return
|
||||
render(plain: '{"success":true}') # report that the operation is successful
|
||||
nil
|
||||
end
|
||||
|
||||
# getting files information
|
||||
def files
|
||||
file_id = params[:fileId]
|
||||
filesInfo = DocumentHelper.get_files_info(file_id) # get the information about the file specified by a file id
|
||||
render json: filesInfo
|
||||
files_info = DocumentHelper.get_files_info(file_id) # get the information about the file specified by a file id
|
||||
render(json: files_info)
|
||||
end
|
||||
|
||||
# downloading a csv file
|
||||
def csv
|
||||
file_name = "csv.csv"
|
||||
csvPath = Rails.root.join('assets', 'document-templates', 'sample', file_name)
|
||||
file_name = 'csv.csv'
|
||||
csv_path = Rails.root.join('assets', 'document-templates', 'sample', file_name)
|
||||
|
||||
# add headers to the response to specify the page parameters
|
||||
response.headers['Content-Length'] = File.size(csvPath).to_s
|
||||
response.headers['Content-Type'] = MimeMagic.by_path(csvPath).type
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8\'\'" + ERB::Util.url_encode(file_name)
|
||||
response.headers['Content-Length'] = File.size(csv_path).to_s
|
||||
response.headers['Content-Type'] = MimeMagic.by_path(csv_path).type
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8''#{ERB::Util.url_encode(file_name)}"
|
||||
|
||||
send_file csvPath, :x_sendfile => true
|
||||
send_file(csv_path, x_sendfile: true)
|
||||
end
|
||||
|
||||
# downloading an assets file
|
||||
@ -285,180 +298,173 @@ class HomeController < ApplicationController
|
||||
|
||||
response.headers['Content-Length'] = File.size(asset_path).to_s
|
||||
response.headers['Content-Type'] = MimeMagic.by_path(asset_path).type
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8\'\'" + ERB::Util.url_encode(file_name)
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8''#{ERB::Util.url_encode(file_name)}"
|
||||
|
||||
send_file asset_path, :x_sendfile => true
|
||||
send_file(asset_path, x_sendfile: true)
|
||||
end
|
||||
|
||||
|
||||
# downloading a file
|
||||
def download
|
||||
begin
|
||||
file_name = File.basename(params[:fileName])
|
||||
user_address = params[:userAddress]
|
||||
isEmbedded = params[:dmode]
|
||||
file_name = File.basename(params[:fileName])
|
||||
user_address = params[:userAddress]
|
||||
is_embedded = params[:dmode]
|
||||
|
||||
if JwtHelper.is_enabled && isEmbedded == nil && user_address != nil && JwtHelper.use_for_request
|
||||
jwtHeader = HomeController.config_manager.jwt_header;
|
||||
if request.headers[jwtHeader]
|
||||
hdr = request.headers[jwtHeader]
|
||||
hdr.slice!(0, "Bearer ".length)
|
||||
token = JwtHelper.decode(hdr)
|
||||
end
|
||||
if !token || token.eql?("")
|
||||
render plain: "JWT validation failed", :status => 403
|
||||
return
|
||||
end
|
||||
if JwtHelper.enabled? && is_embedded.nil? && !user_address.nil? && JwtHelper.use_for_request
|
||||
jwt_header = HomeController.config_manager.jwt_header
|
||||
if request.headers[jwt_header]
|
||||
hdr = request.headers[jwt_header]
|
||||
hdr.slice!(0, 'Bearer '.length)
|
||||
token = JwtHelper.decode(hdr)
|
||||
end
|
||||
|
||||
file_path = DocumentHelper.forcesave_path(file_name, user_address, false) # get the path to the force saved document version
|
||||
if file_path.eql?("")
|
||||
file_path = DocumentHelper.storage_path(file_name, user_address) # or to the original document
|
||||
if !token || token.eql?('')
|
||||
render(plain: 'JWT validation failed', status: :forbidden)
|
||||
return
|
||||
end
|
||||
|
||||
# add headers to the response to specify the page parameters
|
||||
response.headers['Content-Length'] = File.size(file_path).to_s
|
||||
response.headers['Content-Type'] = MimeMagic.by_path(file_path).eql?(nil) ? nil : MimeMagic.by_path(file_path).type
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8\'\'" + ERB::Util.url_encode(file_name)
|
||||
|
||||
send_file file_path, :x_sendfile => true
|
||||
rescue => ex
|
||||
render plain: '{ "error": "File not found"}'
|
||||
end
|
||||
|
||||
# get the path to the force saved document version
|
||||
file_path = DocumentHelper.forcesave_path(file_name, user_address, false)
|
||||
if file_path.eql?('')
|
||||
file_path = DocumentHelper.storage_path(file_name, user_address) # or to the original document
|
||||
end
|
||||
|
||||
# add headers to the response to specify the page parameters
|
||||
response.headers['Content-Length'] = File.size(file_path).to_s
|
||||
response.headers['Content-Type'] =
|
||||
MimeMagic.by_path(file_path).eql?(nil) ? nil : MimeMagic.by_path(file_path).type
|
||||
response.headers['Content-Disposition'] = "attachment;filename*=UTF-8''#{ERB::Util.url_encode(file_name)}"
|
||||
|
||||
send_file(file_path, x_sendfile: true)
|
||||
rescue StandardError
|
||||
render(plain: '{ "error": "File not found"}')
|
||||
end
|
||||
|
||||
# Save Copy as...
|
||||
def saveas
|
||||
begin
|
||||
body = JSON.parse(request.body.read)
|
||||
file_url = body["url"]
|
||||
title = body["title"]
|
||||
file_name = DocumentHelper.get_correct_name(title, nil)
|
||||
extension = File.extname(file_name).downcase
|
||||
all_exts = DocumentHelper.convert_exts + DocumentHelper.edited_exts + DocumentHelper.viewed_exts + DocumentHelper.fill_forms_exts
|
||||
body = JSON.parse(request.body.read)
|
||||
file_url = body['url']
|
||||
title = body['title']
|
||||
file_name = DocumentHelper.get_correct_name(title, nil)
|
||||
extension = File.extname(file_name).downcase
|
||||
all_exts = DocumentHelper.convert_exts +
|
||||
DocumentHelper.edited_exts +
|
||||
DocumentHelper.viewed_exts +
|
||||
DocumentHelper.fill_forms_exts
|
||||
|
||||
unless all_exts.include?(extension)
|
||||
render plain: '{"error": "File type is not supported"}'
|
||||
return
|
||||
end
|
||||
|
||||
uri = URI.parse(file_url) # create the request url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
|
||||
DocumentHelper.verify_ssl(file_url, http)
|
||||
|
||||
req = Net::HTTP::Get.new(uri.request_uri) # create the get requets
|
||||
res = http.request(req)
|
||||
data = res.body
|
||||
|
||||
if data.size <= 0 || data.size > HomeController.config_manager.maximum_file_size
|
||||
render plain: '{"error": "File size is incorrect"}'
|
||||
return
|
||||
end
|
||||
|
||||
File.open(DocumentHelper.storage_path(file_name, nil), 'wb') do |file|
|
||||
file.write(data)
|
||||
end
|
||||
user = Users.get_user(params[:userId])
|
||||
DocumentHelper.create_meta(file_name, user.id, user.name, nil) # create meta data of the new file
|
||||
|
||||
render plain: '{"file" : "' + file_name + '"}'
|
||||
return
|
||||
rescue => ex
|
||||
render plain: '{"error":1, "message": "' + ex.message + '"}'
|
||||
unless all_exts.include?(extension)
|
||||
render(plain: '{"error": "File type is not supported"}')
|
||||
return
|
||||
end
|
||||
|
||||
uri = URI.parse(file_url) # create the request url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
|
||||
DocumentHelper.verify_ssl(file_url, http)
|
||||
|
||||
req = Net::HTTP::Get.new(uri.request_uri) # create the get requets
|
||||
res = http.request(req)
|
||||
data = res.body
|
||||
|
||||
if data.size <= 0 || data.size > HomeController.config_manager.maximum_file_size
|
||||
render(plain: '{"error": "File size is incorrect"}')
|
||||
return
|
||||
end
|
||||
|
||||
File.binwrite(DocumentHelper.storage_path(file_name, nil), data)
|
||||
user = Users.get_user(params[:userId])
|
||||
DocumentHelper.create_meta(file_name, user.id, user.name, nil) # create meta data of the new file
|
||||
|
||||
render(plain: "{\"file\" : \"#{file_name}\"}")
|
||||
nil
|
||||
rescue StandardError => e
|
||||
render(plain: "{\"error\":1, \"message\": \"#{e.message}\"}")
|
||||
nil
|
||||
end
|
||||
|
||||
# Rename...
|
||||
def rename
|
||||
body = JSON.parse(request.body.read)
|
||||
dockey = body["dockey"]
|
||||
newfilename = body["newfilename"]
|
||||
# Rename...
|
||||
def rename
|
||||
body = JSON.parse(request.body.read)
|
||||
dockey = body['dockey']
|
||||
newfilename = body['newfilename']
|
||||
|
||||
orig_ext = '.' + body["ext"]
|
||||
cur_ext = File.extname(newfilename).downcase
|
||||
if orig_ext != cur_ext
|
||||
newfilename += orig_ext
|
||||
orig_ext = ".#{body['ext']}"
|
||||
cur_ext = File.extname(newfilename).downcase
|
||||
newfilename += orig_ext if orig_ext != cur_ext
|
||||
|
||||
meta = {
|
||||
title: newfilename
|
||||
}
|
||||
|
||||
json_data = TrackHelper.command_request('meta', dockey, meta)
|
||||
render(plain: "{ \"result\" : \"#{JSON.dump(json_data)}\"}")
|
||||
end
|
||||
|
||||
# ReferenceData
|
||||
def reference
|
||||
body = JSON.parse(request.body.read)
|
||||
file_name = ''
|
||||
|
||||
if body.key?('referenceData')
|
||||
reference_data = body['referenceData']
|
||||
instance_id = reference_data['instanceId']
|
||||
if instance_id == DocumentHelper.get_server_url(false)
|
||||
file_key = JSON.parse(reference_data['fileKey'])
|
||||
user_address = file_key['userAddress']
|
||||
file_name = file_key['fileName'] if user_address == DocumentHelper.cur_user_host_address(nil)
|
||||
end
|
||||
|
||||
meta = {
|
||||
:title => newfilename
|
||||
}
|
||||
|
||||
json_data = TrackHelper.command_request("meta", dockey, meta)
|
||||
render plain: '{ "result" : "' + JSON.dump(json_data) + '"}'
|
||||
end
|
||||
|
||||
#ReferenceData
|
||||
def reference
|
||||
body = JSON.parse(request.body.read)
|
||||
fileName = ""
|
||||
|
||||
|
||||
if body.key?("referenceData")
|
||||
referenceData = body["referenceData"]
|
||||
instanceId = referenceData["instanceId"]
|
||||
if instanceId == DocumentHelper.get_server_url(false)
|
||||
fileKey = JSON.parse(referenceData["fileKey"])
|
||||
userAddress = fileKey["userAddress"]
|
||||
if userAddress == DocumentHelper.cur_user_host_address(nil)
|
||||
fileName = fileKey["fileName"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
link = body["link"]
|
||||
if fileName.empty? and body.key?("link")
|
||||
if !link.include?(DocumentHelper.get_server_url(false))
|
||||
data = {
|
||||
url: link,
|
||||
directUrl: link
|
||||
}
|
||||
render plain: data.to_json
|
||||
return
|
||||
end
|
||||
|
||||
url_obj = URI(link)
|
||||
query_params = CGI.parse(url_obj.query)
|
||||
fileName = query_params['fileName'].first
|
||||
if !File.exist?(DocumentHelper.storage_path(fileName, nil))
|
||||
render plain: '{ "error": "File is not exist"}'
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if fileName.empty? and body.key?("path")
|
||||
path = File.basename(body["path"])
|
||||
if File.exist?(DocumentHelper.storage_path(path, nil))
|
||||
fileName = path
|
||||
end
|
||||
end
|
||||
|
||||
if fileName.empty?
|
||||
render plain: '{ "error": "File not found"}'
|
||||
link = body['link']
|
||||
if file_name.empty? && body.key?('link')
|
||||
unless link.include?(DocumentHelper.get_server_url(false))
|
||||
data = {
|
||||
url: link,
|
||||
directUrl: link
|
||||
}
|
||||
render(plain: data.to_json)
|
||||
return
|
||||
end
|
||||
|
||||
data = {
|
||||
:fileType => File.extname(fileName).downcase.delete("."),
|
||||
:key => ServiceConverter.generate_revision_id("#{DocumentHelper.cur_user_host_address(nil) + '/' + fileName}.#{File.mtime(DocumentHelper.storage_path(fileName, nil)).to_s}"),
|
||||
:url => DocumentHelper.get_download_url(fileName),
|
||||
:directUrl => body["directUrl"] ? DocumentHelper.get_download_url(fileName, false) : nil,
|
||||
:referenceData => {
|
||||
:instanceId => DocumentHelper.get_server_url(false),
|
||||
:fileKey => {:fileName => fileName,:userAddress => DocumentHelper.cur_user_host_address(nil)}.to_json
|
||||
},
|
||||
:path => fileName,
|
||||
:link => DocumentHelper.get_server_url(false) + '/editor?fileName=' + fileName
|
||||
}
|
||||
|
||||
if JwtHelper.is_enabled
|
||||
data["token"] = JwtHelper.encode(data)
|
||||
url_obj = URI(link)
|
||||
query_params = CGI.parse(url_obj.query)
|
||||
file_name = query_params['fileName'].first
|
||||
unless File.exist?(DocumentHelper.storage_path(file_name, nil))
|
||||
render(plain: '{ "error": "File is not exist"}')
|
||||
return
|
||||
end
|
||||
|
||||
render plain: data.to_json
|
||||
end
|
||||
|
||||
if file_name.empty? && body.key?('path')
|
||||
path = File.basename(body['path'])
|
||||
file_name = path if File.exist?(DocumentHelper.storage_path(path, nil))
|
||||
end
|
||||
|
||||
if file_name.empty?
|
||||
render(plain: '{ "error": "File not found"}')
|
||||
return
|
||||
end
|
||||
|
||||
data = {
|
||||
fileType: File.extname(file_name).downcase.delete('.'),
|
||||
key: ServiceConverter.generate_revision_id(
|
||||
"#{DocumentHelper.cur_user_host_address(nil)}/#{file_name}" \
|
||||
".#{File.mtime(DocumentHelper.storage_path(file_name, nil))}"
|
||||
),
|
||||
url: DocumentHelper.get_download_url(file_name),
|
||||
directUrl: body['directUrl'] ? DocumentHelper.get_download_url(file_name, is_serverUrl: false) : nil,
|
||||
referenceData: {
|
||||
instanceId: DocumentHelper.get_server_url(false),
|
||||
fileKey: { fileName: file_name, userAddress: DocumentHelper.cur_user_host_address(nil) }.to_json
|
||||
},
|
||||
path: file_name,
|
||||
link: "#{DocumentHelper.get_server_url(false)}/editor?fileName=#{file_name}"
|
||||
}
|
||||
|
||||
data['token'] = JwtHelper.encode(data) if JwtHelper.enabled?
|
||||
|
||||
render(plain: data.to_json)
|
||||
end
|
||||
|
||||
def restore
|
||||
body = JSON.parse(request.body.read)
|
||||
|
||||
@ -472,7 +478,7 @@ class HomeController < ApplicationController
|
||||
DocumentHelper.init(request.remote_ip, request.base_url)
|
||||
file_model = FileModel.new(
|
||||
{
|
||||
'file_name': source_basename
|
||||
file_name: source_basename
|
||||
}
|
||||
)
|
||||
|
||||
@ -497,13 +503,13 @@ class HomeController < ApplicationController
|
||||
|
||||
bumped_changes_file = bumped_version_directory.join('changes.json')
|
||||
bumped_changes = {
|
||||
'serverVersion': nil,
|
||||
'changes': [
|
||||
serverVersion: nil,
|
||||
changes: [
|
||||
{
|
||||
'created': Time.now.to_formatted_s(:db),
|
||||
'user': {
|
||||
'id': user.id,
|
||||
'name': user.name
|
||||
created: Time.zone.now.to_fs(:db),
|
||||
user: {
|
||||
id: user.id,
|
||||
name: user.name
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -515,15 +521,19 @@ class HomeController < ApplicationController
|
||||
FileUtils.cp(source_file, bumped_file)
|
||||
FileUtils.cp(recovery_file, source_file)
|
||||
|
||||
render json: {
|
||||
error: nil,
|
||||
success: true
|
||||
}
|
||||
rescue => error
|
||||
render(
|
||||
json: {
|
||||
error: nil,
|
||||
success: true
|
||||
}
|
||||
)
|
||||
rescue StandardError => e
|
||||
response.status = :internal_server_error
|
||||
render json: {
|
||||
error: error.message,
|
||||
success: false
|
||||
}
|
||||
render(
|
||||
json: {
|
||||
error: e.message,
|
||||
success: false
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
require 'pathname'
|
||||
require 'sorbet-runtime'
|
||||
|
||||
# Struct representing a document format with properties.
|
||||
class Format < T::Struct
|
||||
extend T::Sig
|
||||
|
||||
@ -40,6 +41,7 @@ class Format < T::Struct
|
||||
end
|
||||
end
|
||||
|
||||
# FormatManager is responsible for managing document formats and providing various lists of supported extensions.
|
||||
class FormatManager
|
||||
extend T::Sig
|
||||
|
||||
@ -76,7 +78,7 @@ class FormatManager
|
||||
def editable
|
||||
all.filter do |format|
|
||||
format.actions.include?('edit') ||
|
||||
format.actions.include?('lossy-edit')
|
||||
format.actions.include?('lossy-edit')
|
||||
end
|
||||
end
|
||||
|
||||
@ -136,6 +138,7 @@ class FormatManager
|
||||
sig { returns(T::Array[Format]) }
|
||||
def all
|
||||
return @all if defined?(@all)
|
||||
|
||||
content = file.read
|
||||
hash = JSON.parse(content)
|
||||
@all ||= hash.map do |item|
|
||||
@ -143,15 +146,13 @@ class FormatManager
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { returns(Pathname) }
|
||||
def file
|
||||
private def file
|
||||
directory.join('onlyoffice-docs-formats.json')
|
||||
end
|
||||
|
||||
sig { returns(Pathname) }
|
||||
def directory
|
||||
private def directory
|
||||
current_directory = Pathname(T.must(__dir__))
|
||||
directory = current_directory.join('..', '..', 'assets', 'document-formats')
|
||||
directory.cleanpath
|
||||
|
||||
@ -21,6 +21,7 @@ require 'json'
|
||||
require 'test/unit'
|
||||
require_relative 'format'
|
||||
|
||||
# Test case for the Format class.
|
||||
class FormatTests < Test::Unit::TestCase
|
||||
def test_generates_extension
|
||||
content =
|
||||
@ -39,6 +40,7 @@ class FormatTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "all" formats.
|
||||
class FormatManagerAllTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
@ -46,6 +48,7 @@ class FormatManagerAllTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "documents" formats.
|
||||
class FormatManagerDocumentsTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
@ -53,6 +56,7 @@ class FormatManagerDocumentsTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "presentations" formats.
|
||||
class FormatManagerPresentationsTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
@ -60,6 +64,7 @@ class FormatManagerPresentationsTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "spreadsheets" formats.
|
||||
class FormatManagerSpreadsheetsTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
@ -67,6 +72,7 @@ class FormatManagerSpreadsheetsTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "all convertible" formats.
|
||||
class FormatManagerConvertibleTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
@ -74,6 +80,7 @@ class FormatManagerConvertibleTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "all editable" formats.
|
||||
class FormatManagerEditableTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
@ -81,6 +88,7 @@ class FormatManagerEditableTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "all viewable" formats.
|
||||
class FormatManagerViewableTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
@ -88,6 +96,7 @@ class FormatManagerViewableTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for the FormatManager class, checks availability "all filable" formats.
|
||||
class FormatManagerFilableTests < Test::Unit::TestCase
|
||||
def test_loads
|
||||
format_manager = FormatManager.new
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -14,5 +16,6 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Helper for application
|
||||
module ApplicationHelper
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -14,5 +16,6 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Helper for home
|
||||
module HomeHelper
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -17,6 +19,7 @@
|
||||
require_relative '../configuration/configuration'
|
||||
require_relative '../format/format'
|
||||
|
||||
# Class that provides various utility methods related to documents.
|
||||
class DocumentHelper
|
||||
@config_manager = ConfigurationManager.new
|
||||
@format_manager = FormatManager.new
|
||||
@ -26,318 +29,296 @@ class DocumentHelper
|
||||
attr_reader :format_manager
|
||||
end
|
||||
|
||||
@@runtime_cache = {}
|
||||
@@remote_ip = nil
|
||||
@@base_url = nil
|
||||
@runtime_cache = {}
|
||||
@remote_ip = nil
|
||||
@base_url = nil
|
||||
|
||||
class << self
|
||||
def self.init(ip, url)
|
||||
@remote_ip = ip
|
||||
@base_url = url
|
||||
end
|
||||
|
||||
# define max file size
|
||||
def self.file_size_max
|
||||
DocumentHelper.config_manager.maximum_file_size
|
||||
end
|
||||
|
||||
# all the supported file extensions
|
||||
def self.file_exts
|
||||
DocumentHelper.format_manager.all_extensions
|
||||
end
|
||||
|
||||
def self.fill_forms_exts
|
||||
DocumentHelper.format_manager.fillable_extensions
|
||||
end
|
||||
|
||||
# file extensions that can be viewed
|
||||
def self.viewed_exts
|
||||
DocumentHelper.format_manager.viewable_extensions
|
||||
end
|
||||
|
||||
# file extensions that can be edited
|
||||
def self.edited_exts
|
||||
DocumentHelper.format_manager.editable_extensions
|
||||
end
|
||||
|
||||
# file extensions that can be converted
|
||||
def self.convert_exts
|
||||
DocumentHelper.format_manager.convertible_extensions
|
||||
end
|
||||
|
||||
# get current user host address
|
||||
def self.cur_user_host_address(user_address)
|
||||
(user_address.nil? ? @remote_ip : user_address).gsub(/[^0-9\-.a-zA-Z_=]/, '_')
|
||||
end
|
||||
|
||||
# get the storage path of the given file
|
||||
def self.storage_path(file_name, user_address)
|
||||
directory = DocumentHelper.config_manager.storage_path.join(cur_user_host_address(user_address))
|
||||
|
||||
# create a new directory if it doesn't exist
|
||||
FileUtils.mkdir_p(directory) unless File.directory?(directory)
|
||||
|
||||
# put the given file to this directory
|
||||
File.join(directory, File.basename(file_name))
|
||||
end
|
||||
|
||||
# get the path to the forcesaved file version
|
||||
def self.forcesave_path(file_name, user_address, create)
|
||||
directory = DocumentHelper.config_manager.storage_path.join(cur_user_host_address(user_address))
|
||||
|
||||
# the directory with host address doesn't exist
|
||||
return '' unless File.directory?(directory)
|
||||
|
||||
# get the path to the history of the given file
|
||||
directory = File.join(directory, "#{File.basename(file_name)}-hist")
|
||||
unless File.directory?(directory)
|
||||
return '' unless create
|
||||
|
||||
FileUtils.mkdir_p(directory) # create history directory if it doesn't exist
|
||||
|
||||
# the history directory doesn't exist and we are not supposed to create it
|
||||
|
||||
def init (ip, url)
|
||||
@@remote_ip = ip
|
||||
@@base_url = url
|
||||
end
|
||||
|
||||
# define max file size
|
||||
def file_size_max
|
||||
DocumentHelper.config_manager.maximum_file_size
|
||||
end
|
||||
directory = File.join(directory, File.basename(file_name)) # get the path to the given file
|
||||
return '' if !File.file?(directory) && !create
|
||||
|
||||
# all the supported file extensions
|
||||
def file_exts
|
||||
DocumentHelper.format_manager.all_extensions
|
||||
end
|
||||
directory.to_s
|
||||
end
|
||||
|
||||
def fill_forms_exts
|
||||
DocumentHelper.format_manager.fillable_extensions
|
||||
end
|
||||
# get the path to the file history
|
||||
def self.history_dir(storage_path)
|
||||
directory = "#{storage_path}-hist"
|
||||
|
||||
# file extensions that can be viewed
|
||||
def viewed_exts
|
||||
DocumentHelper.format_manager.viewable_extensions
|
||||
end
|
||||
# create history directory if it doesn't exist
|
||||
FileUtils.mkdir_p(directory) unless File.directory?(directory)
|
||||
|
||||
# file extensions that can be edited
|
||||
def edited_exts
|
||||
DocumentHelper.format_manager.editable_extensions
|
||||
end
|
||||
directory
|
||||
end
|
||||
|
||||
# file extensions that can be converted
|
||||
def convert_exts
|
||||
DocumentHelper.format_manager.convertible_extensions
|
||||
end
|
||||
# get the path to the specified file version
|
||||
def self.version_dir(hist_dir, ver)
|
||||
File.join(hist_dir, ver.to_s)
|
||||
end
|
||||
|
||||
# get current user host address
|
||||
def cur_user_host_address(user_address)
|
||||
(user_address == nil ? @@remote_ip : user_address).gsub(/[^0-9\-.a-zA-Z_=]/, '_');
|
||||
end
|
||||
# get the last file version
|
||||
def self.get_file_version(hist_dir)
|
||||
return 1 unless Dir.exist?(hist_dir)
|
||||
|
||||
# get the storage path of the given file
|
||||
def storage_path(file_name, user_address)
|
||||
directory = DocumentHelper.config_manager.storage_path.join(cur_user_host_address(user_address))
|
||||
ver = 1
|
||||
Dir.foreach(hist_dir) do |e| # run through all the file versions
|
||||
next if e.eql?('.')
|
||||
next if e.eql?('..')
|
||||
|
||||
# create a new directory if it doesn't exist
|
||||
unless File.directory?(directory)
|
||||
FileUtils.mkdir_p(directory)
|
||||
end
|
||||
|
||||
# put the given file to this directory
|
||||
File.join(directory, File.basename(file_name))
|
||||
end
|
||||
|
||||
# get the path to the forcesaved file version
|
||||
def forcesave_path(file_name, user_address, create)
|
||||
directory = DocumentHelper.config_manager.storage_path.join(cur_user_host_address(user_address))
|
||||
|
||||
# the directory with host address doesn't exist
|
||||
unless File.directory?(directory)
|
||||
return ""
|
||||
end
|
||||
|
||||
directory = File.join(directory,"#{File.basename(file_name)}-hist") # get the path to the history of the given file
|
||||
unless File.directory?(directory)
|
||||
if create
|
||||
FileUtils.mkdir_p(directory) # create history directory if it doesn't exist
|
||||
else
|
||||
return "" # the history directory doesn't exist and we are not supposed to create it
|
||||
end
|
||||
end
|
||||
|
||||
directory = File.join(directory, File.basename(file_name)) # get the path to the given file
|
||||
unless File.file?(directory)
|
||||
if !create
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
return directory.to_s
|
||||
end
|
||||
|
||||
# get the path to the file history
|
||||
def history_dir(storage_path)
|
||||
directory = "#{storage_path}-hist"
|
||||
|
||||
# create history directory if it doesn't exist
|
||||
unless File.directory?(directory)
|
||||
FileUtils.mkdir_p(directory)
|
||||
end
|
||||
|
||||
return directory
|
||||
end
|
||||
|
||||
# get the path to the specified file version
|
||||
def version_dir(hist_dir, ver)
|
||||
return File.join(hist_dir, ver.to_s)
|
||||
end
|
||||
|
||||
# get the last file version
|
||||
def get_file_version(hist_dir)
|
||||
if !Dir.exist?(hist_dir)
|
||||
return 1
|
||||
end
|
||||
|
||||
ver = 1
|
||||
Dir.foreach(hist_dir) {|e| # run through all the file versions
|
||||
next if e.eql?(".")
|
||||
next if e.eql?("..")
|
||||
if File.directory?(File.join(hist_dir, e))
|
||||
ver += 1 # and count them
|
||||
end
|
||||
}
|
||||
|
||||
return ver
|
||||
end
|
||||
|
||||
# get the correct file name if such a name already exists
|
||||
def get_correct_name(file_name, user_address)
|
||||
maxName = 50
|
||||
ext = File.extname(file_name) # get file extension
|
||||
# get file name without extension
|
||||
base_name = File.basename(file_name, ext)[0...maxName] + (file_name.length > maxName ? '[...]' : '')
|
||||
name = base_name + ext.downcase # get full file name
|
||||
index = 1
|
||||
|
||||
while File.exist?(storage_path(name, user_address)) # if the file with such a name already exists in this directory
|
||||
name = base_name + ' (' + index.to_s + ')' + ext.downcase # add an index after its base name
|
||||
index = index + 1
|
||||
end
|
||||
|
||||
name
|
||||
end
|
||||
|
||||
# get all the stored files from the folder
|
||||
def get_stored_files(user_address)
|
||||
directory = DocumentHelper.config_manager.storage_path.join(cur_user_host_address(user_address))
|
||||
|
||||
arr = [];
|
||||
|
||||
if Dir.exist?(directory)
|
||||
Dir.foreach(directory) {|e| # run through all the elements from the folder
|
||||
next if e.eql?(".")
|
||||
next if e.eql?("..")
|
||||
next if File.directory?(File.join(directory, e)) # if the element is a directory, skip it
|
||||
|
||||
arr.push(e) # push the file to the array
|
||||
}
|
||||
end
|
||||
|
||||
return arr
|
||||
end
|
||||
|
||||
# create file meta information
|
||||
def create_meta(file_name, uid, uname, user_address)
|
||||
hist_dir = history_dir(storage_path(file_name, user_address)) # get the path to the file history
|
||||
|
||||
# write user name, user uid and the creation time to the json object
|
||||
json = {
|
||||
:created => Time.now.to_formatted_s(:db),
|
||||
:uid => uid,
|
||||
:uname => uname
|
||||
}
|
||||
|
||||
# write file meta information to the createdInfo.json file
|
||||
File.open(File.join(hist_dir, "createdInfo.json"), 'wb') do |file|
|
||||
file.write(json.to_json)
|
||||
if File.directory?(File.join(hist_dir, e))
|
||||
ver += 1 # and count them
|
||||
end
|
||||
end
|
||||
|
||||
# create demo document
|
||||
def create_demo(file_ext, sample, user)
|
||||
demo_name = (sample == 'true' ? 'sample.' : 'new.') + file_ext
|
||||
file_name = get_correct_name(demo_name, nil) # get the correct file name if such a name already exists
|
||||
ver
|
||||
end
|
||||
|
||||
src = Rails.root.join('assets', 'document-templates', sample == 'true' ? 'sample' : 'new', demo_name) # save sample document of a necessary extension to the storage directory
|
||||
dest = storage_path file_name, nil
|
||||
# get the correct file name if such a name already exists
|
||||
def self.get_correct_name(file_name, user_address)
|
||||
max_name = 50
|
||||
ext = File.extname(file_name) # get file extension
|
||||
# get file name without extension
|
||||
base_name = File.basename(file_name, ext)[0...max_name] + (file_name.length > max_name ? '[...]' : '')
|
||||
name = base_name + ext.downcase # get full file name
|
||||
index = 1
|
||||
|
||||
FileUtils.cp src, dest
|
||||
|
||||
# save file meta data to the file
|
||||
|
||||
create_meta(file_name, user.id, user.name, nil)
|
||||
|
||||
file_name
|
||||
# if the file with such a name already exists in this directory
|
||||
while File.exist?(storage_path(name, user_address))
|
||||
name = "#{base_name} (#{index})#{ext.downcase}" # add an index after its base name
|
||||
index += 1
|
||||
end
|
||||
|
||||
# get file url
|
||||
def get_file_uri(file_name, for_document_server)
|
||||
uri = get_server_url(for_document_server) + '/' + DocumentHelper.config_manager.storage_path.to_s + '/' + cur_user_host_address(nil) + '/' + ERB::Util.url_encode(file_name)
|
||||
name
|
||||
end
|
||||
|
||||
return uri
|
||||
end
|
||||
# get all the stored files from the folder
|
||||
def self.get_stored_files(user_address)
|
||||
directory = DocumentHelper.config_manager.storage_path.join(cur_user_host_address(user_address))
|
||||
|
||||
# get history path url
|
||||
def get_historypath_uri(file_name,version,file,is_serverUrl=true)
|
||||
# for redirection to my link
|
||||
user_host = is_serverUrl ? '&userAddress=' + cur_user_host_address(nil) : ""
|
||||
uri = get_server_url(is_serverUrl) + '/downloadhistory/?fileName=' + ERB::Util.url_encode(file_name) + '&ver='+ version.to_s + '&file='+ ERB::Util.url_encode(file) + user_host
|
||||
return uri
|
||||
end
|
||||
arr = []
|
||||
|
||||
# get server url
|
||||
def get_server_url(for_document_server)
|
||||
if for_document_server && DocumentHelper.config_manager.example_uri
|
||||
return DocumentHelper.config_manager.example_uri.to_s
|
||||
else
|
||||
return @@base_url
|
||||
if Dir.exist?(directory)
|
||||
Dir.foreach(directory) do |e| # run through all the elements from the folder
|
||||
next if e.eql?('.')
|
||||
next if e.eql?('..')
|
||||
next if File.directory?(File.join(directory, e)) # if the element is a directory, skip it
|
||||
|
||||
arr.push(e) # push the file to the array
|
||||
end
|
||||
end
|
||||
|
||||
# get callback url
|
||||
def get_callback(file_name)
|
||||
arr
|
||||
end
|
||||
|
||||
get_server_url(true) + '/track?fileName=' + ERB::Util.url_encode(file_name) + '&userAddress=' + cur_user_host_address(nil)
|
||||
# create file meta information
|
||||
def self.create_meta(file_name, uid, uname, user_address)
|
||||
hist_dir = history_dir(storage_path(file_name, user_address)) # get the path to the file history
|
||||
|
||||
end
|
||||
# write user name, user uid and the creation time to the json object
|
||||
json = {
|
||||
created: Time.zone.now.to_fs(:db),
|
||||
uid:,
|
||||
uname:
|
||||
}
|
||||
|
||||
# get url to the created file
|
||||
def get_create_url(document_type)
|
||||
# write file meta information to the createdInfo.json file
|
||||
File.binwrite(File.join(hist_dir, 'createdInfo.json'), json.to_json)
|
||||
end
|
||||
|
||||
get_server_url(false) + '/sample?fileExt=' + get_internal_extension(document_type).delete('.')
|
||||
# create demo document
|
||||
def self.create_demo(file_ext, sample, user)
|
||||
demo_name = (sample == 'true' ? 'sample.' : 'new.') + file_ext
|
||||
file_name = get_correct_name(demo_name, nil) # get the correct file name if such a name already exists
|
||||
|
||||
end
|
||||
# save sample document of a necessary extension to the storage directory
|
||||
src = Rails.root.join('assets', 'document-templates', sample == 'true' ? 'sample' : 'new', demo_name)
|
||||
dest = storage_path(file_name, nil)
|
||||
|
||||
# get url to download a file
|
||||
def get_download_url(file_name, is_serverUrl=true)
|
||||
FileUtils.cp(src, dest)
|
||||
|
||||
user_host = is_serverUrl ? '&userAddress=' + cur_user_host_address(nil) : ""
|
||||
get_server_url(is_serverUrl) + '/download?fileName=' + ERB::Util.url_encode(file_name) + user_host
|
||||
# save file meta data to the file
|
||||
|
||||
end
|
||||
create_meta(file_name, user.id, user.name, nil)
|
||||
|
||||
# get internal file extension by its type
|
||||
def get_internal_extension(file_type)
|
||||
file_name
|
||||
end
|
||||
|
||||
case file_type
|
||||
when 'word' # .docx for word type
|
||||
ext = '.docx'
|
||||
when 'cell' # .xlsx for cell type
|
||||
ext = '.xlsx'
|
||||
when 'slide' # .pptx for slide type
|
||||
ext = '.pptx'
|
||||
else
|
||||
ext = '.docx' # the default value is .docx
|
||||
end
|
||||
# get file url
|
||||
def self.get_file_uri(file_name, for_document_server)
|
||||
"#{get_server_url(for_document_server)}/" \
|
||||
"#{DocumentHelper.config_manager.storage_path}/" \
|
||||
"#{cur_user_host_address(nil)}/" \
|
||||
"#{ERB::Util.url_encode(file_name)}"
|
||||
end
|
||||
|
||||
ext
|
||||
end
|
||||
# get history path url
|
||||
def self.get_historypath_uri(file_name, version, file, is_server_url: true)
|
||||
# for redirection to my link
|
||||
user_host = is_server_url ? "&userAddress=#{cur_user_host_address(nil)}" : ''
|
||||
"#{get_server_url(is_server_url)}/downloadhistory/?" \
|
||||
"fileName=#{ERB::Util.url_encode(file_name)}&ver=#{version}" \
|
||||
"&file=#{ERB::Util.url_encode(file)}#{user_host}"
|
||||
end
|
||||
|
||||
# get image url for templates
|
||||
def get_template_image_url(file_type)
|
||||
path = get_server_url(true) + "/assets/"
|
||||
case file_type
|
||||
when 'word' # for word type
|
||||
full_path = path + 'file_docx.svg'
|
||||
when 'cell' # .xlsx for cell type
|
||||
full_path = path + 'file_xlsx.svg'
|
||||
when 'slide' # .pptx for slide type
|
||||
full_path = path + 'file_pptx.svg'
|
||||
else
|
||||
full_path = path + 'file_docx.svg' # the default value is .docx
|
||||
end
|
||||
# get server url
|
||||
def self.get_server_url(for_document_server)
|
||||
return DocumentHelper.config_manager.example_uri.to_s if
|
||||
for_document_server &&
|
||||
DocumentHelper.config_manager.example_uri
|
||||
|
||||
full_path
|
||||
end
|
||||
@base_url
|
||||
end
|
||||
|
||||
# get files information
|
||||
def get_files_info(file_id)
|
||||
result = [];
|
||||
# get callback url
|
||||
def self.get_callback(file_name)
|
||||
"#{get_server_url(true)}/track?" \
|
||||
"fileName=#{ERB::Util.url_encode(file_name)}&" \
|
||||
"userAddress=#{cur_user_host_address(nil)}"
|
||||
end
|
||||
|
||||
for fileName in get_stored_files(nil) # run through all the stored files from the folder
|
||||
directory = storage_path(fileName, nil)
|
||||
uri = cur_user_host_address(nil) + '/' + fileName
|
||||
# get url to the created file
|
||||
def self.get_create_url(document_type)
|
||||
"#{get_server_url(false)}/sample?fileExt=#{get_internal_extension(document_type).delete('.')}"
|
||||
end
|
||||
|
||||
# write file parameters to the info object
|
||||
info = {
|
||||
"version" => get_file_version(history_dir(directory)),
|
||||
"id" => ServiceConverter.generate_revision_id("#{uri}.#{File.mtime(directory).to_s}"),
|
||||
"contentLength" => "#{(File.size(directory)/ 1024.0).round(2)} KB",
|
||||
"pureContentLength" => File.size(directory),
|
||||
"title" => fileName,
|
||||
"updated" => File.mtime(directory)
|
||||
}
|
||||
# get url to download a file
|
||||
def self.get_download_url(file_name, is_server_url: true)
|
||||
user_host = is_server_url ? "&userAddress=#{cur_user_host_address(nil)}" : ''
|
||||
"#{get_server_url(is_server_url)}/download?fileName=#{ERB::Util.url_encode(file_name)}#{user_host}"
|
||||
end
|
||||
|
||||
if file_id == nil # if file id is undefined
|
||||
result.push(info) # push info object to the response array
|
||||
else # if file id is defined
|
||||
if file_id.eql?(info["id"]) # and it is equal to the document key value
|
||||
result.push(info) # response object will be equal to the info object
|
||||
return result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if file_id != nil
|
||||
return "\"File not found\""
|
||||
else
|
||||
return result
|
||||
end
|
||||
end
|
||||
# enable ignore certificate
|
||||
def verify_ssl(file_uri, http)
|
||||
if file_uri.start_with?('https') && DocumentHelper.config_manager.ssl_verify_peer_mode_enabled
|
||||
http.use_ssl = true
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # set the flags for the server certificate verification at the beginning of SSL session
|
||||
end
|
||||
# get internal file extension by its type
|
||||
def self.get_internal_extension(file_type)
|
||||
case file_type
|
||||
when 'word' # .docx for word type
|
||||
'.docx'
|
||||
when 'cell' # .xlsx for cell type
|
||||
'.xlsx'
|
||||
when 'slide' # .pptx for slide type
|
||||
'.pptx'
|
||||
else
|
||||
'.docx' # the default value is .docx
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
# get image url for templates
|
||||
def self.get_template_image_url(file_type)
|
||||
path = "#{get_server_url(true)}/assets/"
|
||||
case file_type
|
||||
when 'word' # for word type
|
||||
"#{path}file_docx.svg"
|
||||
when 'cell' # .xlsx for cell type
|
||||
"#{path}file_xlsx.svg"
|
||||
when 'slide' # .pptx for slide type
|
||||
"#{path}file_pptx.svg"
|
||||
else
|
||||
"#{path}file_docx.svg" # the default value is .docx
|
||||
end
|
||||
end
|
||||
|
||||
# get files information
|
||||
def self.get_files_info(file_id)
|
||||
result = []
|
||||
|
||||
get_stored_files(nil).each do |file_name| # run through all the stored files from the folder
|
||||
directory = storage_path(file_name, nil)
|
||||
uri = "#{cur_user_host_address(nil)}/#{file_name}"
|
||||
|
||||
# write file parameters to the info object
|
||||
info = {
|
||||
version: get_file_version(history_dir(directory)),
|
||||
id: ServiceConverter.generate_revision_id("#{uri}.#{File.mtime(directory)}"),
|
||||
contentLength: "#{(File.size(directory) / 1024.0).round(2)} KB",
|
||||
pureContentLength: File.size(directory),
|
||||
title: file_name,
|
||||
updated: File.mtime(directory)
|
||||
}
|
||||
|
||||
if file_id.nil? # if file id is undefined
|
||||
result.push(info) # push info object to the response array
|
||||
elsif file_id.eql?(info['id']) # if file id is defined
|
||||
result.push(info) # response object will be equal to the info object
|
||||
return result # and it is equal to the document key value
|
||||
end
|
||||
end
|
||||
|
||||
return '"File not found"' unless file_id.nil?
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
# enable ignore certificate
|
||||
def self.verify_ssl(file_uri, http)
|
||||
return unless file_uri.start_with?('https') && DocumentHelper.config_manager.ssl_verify_peer_mode_enabled
|
||||
|
||||
http.use_ssl = true
|
||||
# set the flags for the server certificate verification at the beginning of SSL session
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -16,16 +18,23 @@
|
||||
|
||||
require_relative '../configuration/configuration'
|
||||
|
||||
# Class for handling file-related operations and information.
|
||||
class FileModel
|
||||
|
||||
attr_accessor :file_name, :mode, :type, :user_ip, :lang, :user, :action_data, :direct_url
|
||||
attr_accessor :file_name
|
||||
attr_accessor :mode
|
||||
attr_accessor :type
|
||||
attr_accessor :user_ip
|
||||
attr_accessor :lang
|
||||
attr_accessor :user
|
||||
attr_accessor :action_data
|
||||
attr_accessor :direct_url
|
||||
attr_reader :config_manager
|
||||
|
||||
# set file parameters
|
||||
def initialize(attributes = {})
|
||||
@file_name = attributes[:file_name]
|
||||
@mode = attributes[:mode]
|
||||
@type = attributes[:type]
|
||||
@type = attributes[:type] || 'desktop' # the default platform type is desktop
|
||||
@user_ip = attributes[:user_ip]
|
||||
@lang = attributes[:lang]
|
||||
@user = attributes[:user]
|
||||
@ -34,10 +43,6 @@ class FileModel
|
||||
@config_manager = ConfigurationManager.new
|
||||
end
|
||||
|
||||
def type
|
||||
@type ? @type : "desktop" # the default platform type is desktop
|
||||
end
|
||||
|
||||
# get file extension from its name
|
||||
def file_ext
|
||||
File.extname(@file_name).downcase
|
||||
@ -50,7 +55,14 @@ class FileModel
|
||||
|
||||
# get file uri for document server
|
||||
def file_uri_user
|
||||
@config_manager.storage_path.absolute? ? download_url + "&dmode=emb" : DocumentHelper.get_file_uri(@file_name, false)
|
||||
if @config_manager.storage_path.absolute?
|
||||
"#{download_url}&dmode=emb"
|
||||
else
|
||||
DocumentHelper.get_file_uri(
|
||||
@file_name,
|
||||
false
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# get document type from its name (word, cell or slide)
|
||||
@ -60,9 +72,9 @@ class FileModel
|
||||
|
||||
# generate the document key value
|
||||
def key
|
||||
uri = DocumentHelper.cur_user_host_address(nil) + '/' + @file_name # get current user host address
|
||||
stat = File.mtime(DocumentHelper.storage_path(@file_name, nil)) # get the modification time of the given file
|
||||
return ServiceConverter.generate_revision_id("#{uri}.#{stat.to_s}")
|
||||
uri = "#{DocumentHelper.cur_user_host_address(nil)}/#{@file_name}" # get current user host address
|
||||
stat = File.mtime(DocumentHelper.storage_path(@file_name, nil)) # get the modification time of the given file
|
||||
ServiceConverter.generate_revision_id("#{uri}.#{stat}")
|
||||
end
|
||||
|
||||
# get callback url
|
||||
@ -76,8 +88,8 @@ class FileModel
|
||||
end
|
||||
|
||||
# get url to download a file
|
||||
def download_url(is_serverUrl=true)
|
||||
DocumentHelper.get_download_url(@file_name, is_serverUrl)
|
||||
def download_url(is_server_url: true)
|
||||
DocumentHelper.get_download_url(@file_name, is_server_url:)
|
||||
end
|
||||
|
||||
# get current user host address
|
||||
@ -86,304 +98,377 @@ class FileModel
|
||||
end
|
||||
|
||||
# get config parameters
|
||||
def get_config
|
||||
editorsmode = @mode ? @mode : "edit" # mode: view/edit/review/comment/fillForms/embedded
|
||||
canEdit = DocumentHelper.edited_exts.include?(file_ext) # check if the document can be edited
|
||||
if (!canEdit && editorsmode.eql?("edit") || editorsmode.eql?("fillForms")) && DocumentHelper.fill_forms_exts.include?(file_ext)
|
||||
editorsmode = "fillForms"
|
||||
canEdit = true
|
||||
def config
|
||||
editors_mode = @mode || 'edit' # mode: view/edit/review/comment/fillForms/embedded
|
||||
can_edit = DocumentHelper.edited_exts.include?(file_ext) # check if the document can be edited
|
||||
if ((!can_edit && editors_mode.eql?('edit')) || editors_mode.eql?('fillForms')) &&
|
||||
DocumentHelper.fill_forms_exts.include?(file_ext)
|
||||
editors_mode = 'fillForms'
|
||||
can_edit = true
|
||||
end
|
||||
submitForm = editorsmode.eql?("fillForms") && @user.id.eql?("uid-1") # the Submit form button state
|
||||
mode = canEdit && !editorsmode.eql?("view") ? "edit" : "view"
|
||||
templatesImageUrl = DocumentHelper.get_template_image_url(document_type) # templates image url in the "From Template" section
|
||||
submit_form = editors_mode.eql?('fillForms') && @user.id.eql?('uid-1') # the Submit form button state
|
||||
mode = can_edit && !editors_mode.eql?('view') ? 'edit' : 'view'
|
||||
# templates image url in the "From Template" section
|
||||
templates_image_url = DocumentHelper.get_template_image_url(document_type)
|
||||
templates = [
|
||||
{
|
||||
:image => "",
|
||||
:title => "Blank",
|
||||
:url => create_url
|
||||
image: '',
|
||||
title: 'Blank',
|
||||
url: create_url
|
||||
},
|
||||
{
|
||||
:image => templatesImageUrl,
|
||||
:title => "With sample content",
|
||||
:url => create_url + "&sample=true"
|
||||
image: templates_image_url,
|
||||
title: 'With sample content',
|
||||
url: "#{create_url}&sample=true"
|
||||
}
|
||||
]
|
||||
|
||||
config = {
|
||||
:type => type(),
|
||||
:documentType => document_type,
|
||||
:document => {
|
||||
:title => @file_name,
|
||||
:url => download_url,
|
||||
:directUrl => is_enable_direct_url ? download_url(false) : "",
|
||||
:fileType => file_ext.delete("."),
|
||||
:key => key,
|
||||
:info => {
|
||||
:owner => "Me",
|
||||
:uploaded => Time.now.to_s,
|
||||
:favorite => @user.favorite
|
||||
type:,
|
||||
documentType: document_type,
|
||||
document: {
|
||||
title: @file_name,
|
||||
url: download_url,
|
||||
directUrl: enable_direct_url? ? download_url(is_server_url: false) : '',
|
||||
fileType: file_ext.delete('.'),
|
||||
key:,
|
||||
info: {
|
||||
owner: 'Me',
|
||||
uploaded: Time.zone.now.to_s,
|
||||
favorite: @user.favorite
|
||||
},
|
||||
:permissions => { # the permission for the document to be edited and downloaded or not
|
||||
:comment => !editorsmode.eql?("view") && !editorsmode.eql?("fillForms") && !editorsmode.eql?("embedded") && !editorsmode.eql?("blockcontent"),
|
||||
:copy => !@user.deniedPermissions.include?("copy"),
|
||||
:download => !@user.deniedPermissions.include?("download"),
|
||||
:edit => canEdit && (editorsmode.eql?("edit") || editorsmode.eql?("view") || editorsmode.eql?("filter") || editorsmode.eql?("blockcontent")),
|
||||
:print => !@user.deniedPermissions.include?("print"),
|
||||
:fillForms => !editorsmode.eql?("view") && !editorsmode.eql?("comment") && !editorsmode.eql?("embedded") && !editorsmode.eql?("blockcontent"),
|
||||
:modifyFilter => !editorsmode.eql?("filter"),
|
||||
:modifyContentControl => !editorsmode.eql?("blockcontent"),
|
||||
:review => canEdit && (editorsmode.eql?("edit") || editorsmode.eql?("review")),
|
||||
:chat => !@user.id.eql?("uid-0"),
|
||||
:reviewGroups => @user.reviewGroups,
|
||||
:commentGroups => @user.commentGroups,
|
||||
:userInfoGroups => @user.userInfoGroups,
|
||||
:protect => !@user.deniedPermissions.include?("protect")
|
||||
permissions: { # the permission for the document to be edited and downloaded or not
|
||||
comment: ['view', 'fillForms', 'embedded', 'blockcontent'].exclude?(editors_mode),
|
||||
copy: @user.denied_permissions.exclude?('copy'),
|
||||
download: @user.denied_permissions.exclude?('download'),
|
||||
edit: can_edit && ['edit', 'view', 'filter', 'blockcontent'].include?(editors_mode),
|
||||
print: @user.denied_permissions.exclude?('print'),
|
||||
fillForms: ['view', 'comment', 'embedded', 'blockcontent'].exclude?(editors_mode),
|
||||
modifyFilter: !editors_mode.eql?('filter'),
|
||||
modifyContentControl: !editors_mode.eql?('blockcontent'),
|
||||
review: can_edit && (editors_mode.eql?('edit') || editors_mode.eql?('review')),
|
||||
chat: !@user.id.eql?('uid-0'),
|
||||
reviewGroups: @user.review_groups,
|
||||
commentGroups: @user.comment_groups,
|
||||
userInfoGroups: @user.user_info_groups,
|
||||
protect: @user.denied_permissions.exclude?('protect')
|
||||
},
|
||||
:referenceData => {
|
||||
:instanceId => DocumentHelper.get_server_url(false),
|
||||
:fileKey => !@user.id.eql?("uid-0") ? {:fileName => @file_name,:userAddress => DocumentHelper.cur_user_host_address(nil)}.to_json : nil
|
||||
referenceData: {
|
||||
instanceId: DocumentHelper.get_server_url(false),
|
||||
fileKey: unless @user.id.eql?('uid-0')
|
||||
{
|
||||
fileName: @file_name,
|
||||
userAddress: DocumentHelper.cur_user_host_address(nil)
|
||||
}.to_json
|
||||
end
|
||||
}
|
||||
},
|
||||
:editorConfig => {
|
||||
:actionLink => @action_data ? JSON.parse(@action_data) : nil,
|
||||
:mode => mode,
|
||||
:lang => @lang ? @lang : "en",
|
||||
:callbackUrl => callback_url, # absolute URL to the document storage service
|
||||
:coEditing => editorsmode.eql?("view") && @user.id.eql?("uid-0") ? {
|
||||
:mode => "strict",
|
||||
:change => false
|
||||
} : nil,
|
||||
:createUrl => !@user.id.eql?("uid-0") ? create_url : nil,
|
||||
:templates => @user.templates ? templates : nil,
|
||||
:user => { # the user currently viewing or editing the document
|
||||
:id => !@user.id.eql?("uid-0") ? @user.id : nil,
|
||||
:name => @user.name,
|
||||
:group => @user.group,
|
||||
:image => @user.avatar ? "#{DocumentHelper.get_server_url(true)}/assets/#{@user.id}.png" : nil
|
||||
editorConfig: {
|
||||
actionLink: @action_data ? JSON.parse(@action_data) : nil,
|
||||
mode:,
|
||||
lang: @lang || 'en',
|
||||
callbackUrl: callback_url, # absolute URL to the document storage service
|
||||
coEditing: if editors_mode.eql?('view') && @user.id.eql?('uid-0')
|
||||
{
|
||||
mode: 'strict',
|
||||
change: false
|
||||
}
|
||||
end,
|
||||
createUrl: @user.id.eql?('uid-0') ? nil : create_url,
|
||||
templates: @user.templates ? templates : nil,
|
||||
user: { # the user currently viewing or editing the document
|
||||
id: @user.id.eql?('uid-0') ? nil : @user.id,
|
||||
name: @user.name,
|
||||
group: @user.group,
|
||||
image: @user.avatar ? "#{DocumentHelper.get_server_url(true)}/assets/#{@user.id}.png" : nil
|
||||
},
|
||||
:embedded => { # the parameters for the embedded document type
|
||||
:saveUrl => download_url(false), # the absolute URL that will allow the document to be saved onto the user personal computer
|
||||
:embedUrl => download_url(false), # the absolute URL to the document serving as a source file for the document embedded into the web page
|
||||
:shareUrl => download_url(false), # the absolute URL that will allow other users to share this document
|
||||
:toolbarDocked => "top" # the place for the embedded viewer toolbar (top or bottom)
|
||||
embedded: { # the parameters for the embedded document type
|
||||
# the absolute URL that will allow the document to be saved onto the user personal computer
|
||||
saveUrl: download_url(is_server_url: false),
|
||||
# the absolute URL to the document serving as a source file for the document embedded into the web page
|
||||
embedUrl: download_url(is_server_url: false),
|
||||
# the absolute URL that will allow other users to share this document
|
||||
shareUrl: download_url(is_server_url: false),
|
||||
toolbarDocked: 'top' # the place for the embedded viewer toolbar (top or bottom)
|
||||
},
|
||||
:customization => { # the parameters for the editor interface
|
||||
:about => true, # the About section display
|
||||
:comments => true,
|
||||
:feedback => true, # the Feedback & Support menu button display
|
||||
:forcesave => false, # adding the request for the forced file saving to the callback handler
|
||||
:submitForm => submitForm, # the Submit form button state
|
||||
:goback => {
|
||||
:url => DocumentHelper.get_server_url(false)
|
||||
},
|
||||
customization: { # the parameters for the editor interface
|
||||
about: true, # the About section display
|
||||
comments: true,
|
||||
feedback: true, # the Feedback & Support menu button display
|
||||
forcesave: false, # adding the request for the forced file saving to the callback handler
|
||||
submitForm: submit_form, # the Submit form button state
|
||||
goback: {
|
||||
url: DocumentHelper.get_server_url(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if JwtHelper.is_enabled # check if a secret key to generate token exists or not
|
||||
config["token"] = JwtHelper.encode(config) # encode a payload object into a token and write it to the config
|
||||
if JwtHelper.enabled? # check if a secret key to generate token exists or not
|
||||
config['token'] = JwtHelper.encode(config) # encode a payload object into a token and write it to the config
|
||||
end
|
||||
|
||||
return config
|
||||
config
|
||||
end
|
||||
|
||||
# get document history
|
||||
def get_history
|
||||
def history
|
||||
file_name = @file_name
|
||||
file_ext = File.extname(file_name).downcase
|
||||
doc_key = key()
|
||||
doc_uri = file_uri()
|
||||
doc_key = key
|
||||
file_uri
|
||||
|
||||
hist_dir = DocumentHelper.history_dir(DocumentHelper.storage_path(@file_name, nil)) # get the path to the file history
|
||||
cur_ver = DocumentHelper.get_file_version(hist_dir) # get the file version
|
||||
# get the path to the file history
|
||||
hist_dir = DocumentHelper.history_dir(DocumentHelper.storage_path(@file_name, nil))
|
||||
cur_ver = DocumentHelper.get_file_version(hist_dir) # get the file version
|
||||
|
||||
if (cur_ver > 0) # if file was modified
|
||||
if cur_ver.positive? # if file was modified
|
||||
hist = []
|
||||
histData = {}
|
||||
hist_data = {}
|
||||
|
||||
for i in 1..cur_ver # run through all the file versions
|
||||
(1..cur_ver).each do |i| # run through all the file versions
|
||||
obj = {}
|
||||
dataObj = {}
|
||||
ver_dir = DocumentHelper.version_dir(hist_dir, i) # get the path to the given file version
|
||||
data_obj = {}
|
||||
ver_dir = DocumentHelper.version_dir(hist_dir, i) # get the path to the given file version
|
||||
|
||||
# get document key
|
||||
cur_key = doc_key
|
||||
if (i != cur_ver)
|
||||
File.open(File.join(ver_dir, "key.txt"), 'r') do |file|
|
||||
cur_key = file.read()
|
||||
if i != cur_ver
|
||||
File.open(File.join(ver_dir, 'key.txt'), 'r') do |file|
|
||||
cur_key = file.read
|
||||
end
|
||||
end
|
||||
obj["key"] = cur_key
|
||||
obj["version"] = i
|
||||
obj['key'] = cur_key
|
||||
obj['version'] = i
|
||||
|
||||
if (i == 1) # check if the version number is equal to 1
|
||||
if File.file?(File.join(hist_dir, "createdInfo.json")) # check if the createdInfo.json file with meta data exists
|
||||
File.open(File.join(hist_dir, "createdInfo.json"), 'r') do |file| # open it
|
||||
cr_info = JSON.parse(file.read()) # parse the file content
|
||||
# check if the createdInfo.json file with meta data exists
|
||||
if (i == 1) && File.file?(File.join(hist_dir, 'createdInfo.json'))
|
||||
File.open(File.join(hist_dir, 'createdInfo.json'), 'r') do |file| # open it
|
||||
cr_info = JSON.parse(file.read) # parse the file content
|
||||
|
||||
# write information about changes to the object
|
||||
obj["created"] = cr_info["created"]
|
||||
obj["user"] = {
|
||||
:id => cr_info["uid"],
|
||||
:name => cr_info["uname"]
|
||||
}
|
||||
end
|
||||
# write information about changes to the object
|
||||
obj['created'] = cr_info['created']
|
||||
obj['user'] = {
|
||||
id: cr_info['uid'],
|
||||
name: cr_info['uname']
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# get the history data from the previous file version and write key and url information about it
|
||||
dataObj["fileType"] = file_ext[1..file_ext.length]
|
||||
dataObj["key"] = cur_key
|
||||
dataObj["url"] = i == cur_ver ? doc_uri : DocumentHelper.get_historypath_uri(file_name, i, "prev#{file_ext}")
|
||||
if is_enable_direct_url == true
|
||||
dataObj["directUrl"] = i == cur_ver ? download_url(false) : DocumentHelper.get_historypath_uri(file_name, i, "prev#{file_ext}", false)
|
||||
data_obj['fileType'] = file_ext[1..file_ext.length]
|
||||
data_obj['key'] = cur_key
|
||||
data_obj['url'] =
|
||||
if i == cur_ver
|
||||
DocumentHelper.get_download_url(
|
||||
file_name,
|
||||
true
|
||||
)
|
||||
else
|
||||
DocumentHelper.get_historypath_uri(
|
||||
file_name,
|
||||
i,
|
||||
"prev#{file_ext}"
|
||||
)
|
||||
end
|
||||
if enable_direct_url? == true
|
||||
data_obj['directUrl'] =
|
||||
if i == cur_ver
|
||||
download_url(is_server_url: false)
|
||||
else
|
||||
DocumentHelper.get_historypath_uri(
|
||||
file_name,
|
||||
i,
|
||||
"prev#{file_ext}",
|
||||
false
|
||||
)
|
||||
end
|
||||
end
|
||||
dataObj["version"] = i
|
||||
data_obj['version'] = i
|
||||
|
||||
if (i > 1) # check if the version number is greater than 1
|
||||
if i > 1 # check if the version number is greater than 1
|
||||
changes = nil
|
||||
change = nil
|
||||
File.open(File.join(DocumentHelper.version_dir(hist_dir, i - 1), "changes.json"), 'r') do |file| # get the path to the changes.json file
|
||||
changes = JSON.parse(file.read()) # and parse its content
|
||||
# get the path to the changes.json file
|
||||
File.open(File.join(DocumentHelper.version_dir(hist_dir, i - 1), 'changes.json'), 'r') do |file|
|
||||
changes = JSON.parse(file.read) # and parse its content
|
||||
end
|
||||
|
||||
change = changes["changes"][0]
|
||||
change = changes['changes'][0]
|
||||
|
||||
# write information about changes to the object
|
||||
obj["changes"] = change ? changes["changes"] : nil
|
||||
obj["serverVersion"] = changes["serverVersion"]
|
||||
obj["created"] = change ? change["created"] : nil
|
||||
obj["user"] = change ? change["user"] : nil
|
||||
obj['changes'] = change ? changes['changes'] : nil
|
||||
obj['serverVersion'] = changes['serverVersion']
|
||||
obj['created'] = change ? change['created'] : nil
|
||||
obj['user'] = change ? change['user'] : nil
|
||||
|
||||
prev = histData[(i - 2).to_s] # get the history data from the previous file version
|
||||
dataObj["previous"] = is_enable_direct_url == true ? { # write key and url information about previous file version with optional direct url
|
||||
:fileType => prev["fileType"],
|
||||
:key => prev["key"],
|
||||
:url => prev["url"],
|
||||
:directUrl => prev["directUrl"]
|
||||
} : {
|
||||
:fileType => prev["fileType"],
|
||||
:key => prev["key"],
|
||||
:url => prev["url"]
|
||||
}
|
||||
prev = hist_data[(i - 2).to_s] # get the history data from the previous file version
|
||||
# write key and url information about previous file version with optional direct url
|
||||
data(
|
||||
obj['previous'] = if enable_direct_url? == true
|
||||
{ # write key and url information about previous file version with optional directUrl
|
||||
fileType: prev['fileType'],
|
||||
key: prev['key'],
|
||||
url: prev['url'],
|
||||
directUrl: prev['directUrl']
|
||||
}
|
||||
else
|
||||
{
|
||||
fileType: prev['fileType'],
|
||||
key: prev['key'],
|
||||
url: prev['url']
|
||||
}
|
||||
end
|
||||
)
|
||||
|
||||
# write the path to the diff.zip archive with differences in this file version
|
||||
dataObj["changesUrl"] = DocumentHelper.get_historypath_uri(file_name, i - 1, "diff.zip")
|
||||
diff_path = [hist_dir, (i - 1).to_s, 'diff.zip'].join(File::SEPARATOR)
|
||||
if File.exist?(diff_path)
|
||||
# write the path to the diff.zip archive with differences in this file version
|
||||
data_obj['changesUrl'] = DocumentHelper.get_historypath_uri(file_name, i - 1, 'diff.zip')
|
||||
end
|
||||
end
|
||||
|
||||
if JwtHelper.is_enabled # check if a secret key to generate token exists or not
|
||||
dataObj["token"] = JwtHelper.encode(dataObj) # encode a payload object into a token and write it to the data object
|
||||
if JwtHelper.enabled? # check if a secret key to generate token exists or not
|
||||
# encode a payload object into a token and write it to the data object
|
||||
data_obj['token'] = JwtHelper.encode(data_obj)
|
||||
end
|
||||
|
||||
hist.push(obj) # add object dictionary to the hist list
|
||||
histData[(i - 1).to_s] = dataObj # write data object information to the history data
|
||||
hist.push(obj) # add object dictionary to the hist list
|
||||
hist_data[(i - 1).to_s] = data_obj # write data object information to the history data
|
||||
end
|
||||
|
||||
return {
|
||||
:hist => { # write history information about the current file version to the hist
|
||||
:currentVersion => cur_ver,
|
||||
:history => hist
|
||||
hist: { # write history information about the current file version to the hist
|
||||
currentVersion: cur_ver,
|
||||
history: hist
|
||||
},
|
||||
:histData => histData
|
||||
histData: hist_data
|
||||
}
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# get image information
|
||||
def get_insert_image
|
||||
insert_image = is_enable_direct_url == true ? {
|
||||
:fileType => "png", # image file type
|
||||
:url => DocumentHelper.get_server_url(true) + "/assets/logo.png", # server url to the image
|
||||
:directUrl => DocumentHelper.get_server_url(false) + "/assets/logo.png" # direct url to the image
|
||||
} : {
|
||||
:fileType => "png", # image file type
|
||||
:url => DocumentHelper.get_server_url(true) + "/assets/logo.png" # server url to the image
|
||||
}
|
||||
def insert_image
|
||||
# image file type
|
||||
# server url to the image
|
||||
# direct url to the image
|
||||
insert_image = if enable_direct_url? == true
|
||||
{
|
||||
fileType: 'png', # image file type
|
||||
url: "#{DocumentHelper.get_server_url(true)}/assets/logo.png", # server url to the image
|
||||
directUrl: "#{DocumentHelper.get_server_url(false)}/assets/logo.png" # direct url to the image
|
||||
}
|
||||
else
|
||||
{
|
||||
fileType: 'png', # image file type
|
||||
url: "#{DocumentHelper.get_server_url(true)}/assets/logo.png" # server url to the image
|
||||
}
|
||||
end
|
||||
|
||||
if JwtHelper.is_enabled # check if a secret key to generate token exists or not
|
||||
insert_image["token"] = JwtHelper.encode(insert_image) # encode a payload object into a token and write it to the insert_image object
|
||||
if JwtHelper.enabled? # check if a secret key to generate token exists or not
|
||||
# encode a payload object into a token and write it to the insert_image object
|
||||
insert_image['token'] = JwtHelper.encode(insert_image)
|
||||
end
|
||||
|
||||
return insert_image.to_json.tr("{", "").tr("}","")
|
||||
insert_image.to_json.tr('{', '').tr('}', '')
|
||||
end
|
||||
|
||||
# get compared file information
|
||||
def dataDocument
|
||||
compare_file = is_enable_direct_url == true ? {
|
||||
:fileType => "docx", # file type
|
||||
:url => DocumentHelper.get_server_url(true) + "/asset?fileName=sample.docx", # server url to the compared file
|
||||
:directUrl => DocumentHelper.get_server_url(false) + "/asset?fileName=sample.docx" # direct url to the compared file
|
||||
} : {
|
||||
:fileType => "docx", # file type
|
||||
:url => DocumentHelper.get_server_url(true) + "/asset?fileName=sample.docx" # server url to the compared file
|
||||
}
|
||||
def data_document
|
||||
# file type
|
||||
# server url to the compared file
|
||||
# direct url to the compared file
|
||||
compare_file = if enable_direct_url? == true
|
||||
{
|
||||
fileType: 'docx', # file type
|
||||
# server url to the compared file
|
||||
url: "#{DocumentHelper.get_server_url(true)}/asset?fileName=sample.docx",
|
||||
# direct url to the compared file
|
||||
directUrl: "#{DocumentHelper.get_server_url(false)}/asset?fileName=sample.docx"
|
||||
}
|
||||
else
|
||||
{
|
||||
fileType: 'docx', # file type
|
||||
# server url to the compared file
|
||||
url: "#{DocumentHelper.get_server_url(true)}/asset?fileName=sample.docx"
|
||||
}
|
||||
end
|
||||
|
||||
if JwtHelper.is_enabled # check if a secret key to generate token exists or not
|
||||
compare_file["token"] = JwtHelper.encode(compare_file) # encode a payload object into a token and write it to the compare_file object
|
||||
if JwtHelper.enabled? # check if a secret key to generate token exists or not
|
||||
# encode a payload object into a token and write it to the compare_file object
|
||||
compare_file['token'] = JwtHelper.encode(compare_file)
|
||||
end
|
||||
|
||||
return compare_file
|
||||
|
||||
compare_file
|
||||
end
|
||||
|
||||
# get mail merge recipients information
|
||||
def dataSpreadsheet
|
||||
dataSpreadsheet = is_enable_direct_url == true ? {
|
||||
:fileType => "csv", # file type
|
||||
:url => DocumentHelper.get_server_url(true) + "/csv", # server url to the mail merge recipients file
|
||||
:directUrl => DocumentHelper.get_server_url(false) + "/csv" # direct url to the mail merge recipients file
|
||||
} : {
|
||||
:fileType => "csv", # file type
|
||||
:url => DocumentHelper.get_server_url(true) + "/csv" # server url to the mail merge recipients file
|
||||
}
|
||||
def data_spreadsheet
|
||||
# file type
|
||||
# server url to the mail merge recipients file
|
||||
# direct url to the mail merge recipients file
|
||||
data_spreadsheet = if enable_direct_url? == true
|
||||
{
|
||||
fileType: 'csv', # file type
|
||||
# server url to the mail merge recipients file
|
||||
url: "#{DocumentHelper.get_server_url(true)}/csv",
|
||||
# direct url to the mail merge recipients file
|
||||
directUrl: "#{DocumentHelper.get_server_url(false)}/csv"
|
||||
}
|
||||
else
|
||||
{
|
||||
fileType: 'csv', # file type
|
||||
# server url to the mail merge recipients file
|
||||
url: "#{DocumentHelper.get_server_url(true)}/csv"
|
||||
}
|
||||
end
|
||||
|
||||
if JwtHelper.is_enabled # check if a secret key to generate token exists or not
|
||||
dataSpreadsheet["token"] = JwtHelper.encode(dataSpreadsheet) # encode a payload object into a token and write it to the dataSpreadsheet object
|
||||
if JwtHelper.enabled? # check if a secret key to generate token exists or not
|
||||
# encode a payload object into a token and write it to the data_spreadsheet object
|
||||
data_spreadsheet['token'] = JwtHelper.encode(data_spreadsheet)
|
||||
end
|
||||
|
||||
return dataSpreadsheet
|
||||
data_spreadsheet
|
||||
end
|
||||
|
||||
# get users data for mentions
|
||||
def get_users_mentions
|
||||
return !@user.id.eql?("uid-0") ? Users.get_users_for_mentions(@user.id) : nil
|
||||
def users_mentions
|
||||
@user.id.eql?('uid-0') ? nil : Users.get_users_for_mentions(@user.id)
|
||||
end
|
||||
|
||||
def get_users_info
|
||||
def users_info
|
||||
users_info = []
|
||||
if !@user.id.eql?("uid-0")
|
||||
Users.get_all_users().each do |user_info|
|
||||
u = {
|
||||
id: user_info.id,
|
||||
name: user_info.name,
|
||||
email: user_info.email,
|
||||
group: user_info.group,
|
||||
reviewGroups: user_info.reviewGroups,
|
||||
commentGroups: user_info.commentGroups,
|
||||
userInfoGroups: user_info.userInfoGroups,
|
||||
favorite: user_info.favorite,
|
||||
deniedPermissions: user_info.deniedPermissions,
|
||||
descriptions: user_info.descriptions,
|
||||
templates: user_info.templates,
|
||||
avatar: user_info.avatar
|
||||
}
|
||||
u["image"] = user_info.avatar ? "#{DocumentHelper.get_server_url(true)}/assets/#{user_info.id}.png" : nil
|
||||
users_info.push(u)
|
||||
end
|
||||
return users_info
|
||||
return if @user.id.eql?('uid-0')
|
||||
|
||||
Users.all_users.each do |user_info|
|
||||
u = {
|
||||
id: user_info.id,
|
||||
name: user_info.name,
|
||||
email: user_info.email,
|
||||
group: user_info.group,
|
||||
reviewGroups: user_info.review_groups,
|
||||
commentGroups: user_info.comment_groups,
|
||||
userInfoGroups: user_info.user_info_groups,
|
||||
favorite: user_info.favorite,
|
||||
deniedPermissions: user_info.denied_permissions,
|
||||
descriptions: user_info.descriptions,
|
||||
templates: user_info.templates,
|
||||
avatar: user_info.avatar
|
||||
}
|
||||
u['image'] = user_info.avatar ? "#{DocumentHelper.get_server_url(true)}/assets/#{user_info.id}.png" : nil
|
||||
users_info.push(u)
|
||||
end
|
||||
users_info
|
||||
end
|
||||
|
||||
# get users data for protect
|
||||
def get_users_protect
|
||||
return !@user.id.eql?("uid-0") ? Users.get_users_for_protect(@user.id) : nil
|
||||
def users_protect
|
||||
@user.id.eql?('uid-0') ? nil : Users.get_users_for_protect(@user.id)
|
||||
end
|
||||
|
||||
# get direct url existence flag
|
||||
def is_enable_direct_url
|
||||
return @direct_url != nil && @direct_url == "true"
|
||||
def enable_direct_url?
|
||||
!@direct_url.nil? && @direct_url == 'true'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -16,20 +18,21 @@
|
||||
|
||||
require_relative '../format/format'
|
||||
|
||||
# Determination file type based on extensions, utilizing `@format_manager` for format management.
|
||||
class FileUtility
|
||||
@format_manager = FormatManager.new
|
||||
|
||||
class << self
|
||||
attr_reader :format_manager
|
||||
end
|
||||
|
||||
def get_file_type(file_name)
|
||||
ext = File.extname(file_name).downcase
|
||||
def self.get_file_type(file_name)
|
||||
ext = File.extname(file_name).downcase
|
||||
|
||||
return 'word' if FileUtility.format_manager.document_extensinons.include?(ext)
|
||||
return 'cell' if FileUtility.format_manager.spreadsheet_extensinons.include?(ext)
|
||||
return 'slide' if FileUtility.format_manager.presentation_extensinons.include?(ext)
|
||||
return 'word' if FileUtility.format_manager.document_extensinons.include?(ext)
|
||||
return 'cell' if FileUtility.format_manager.spreadsheet_extensinons.include?(ext)
|
||||
return 'slide' if FileUtility.format_manager.presentation_extensinons.include?(ext)
|
||||
|
||||
'word'
|
||||
end
|
||||
'word'
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -17,37 +19,35 @@
|
||||
require 'jwt'
|
||||
require_relative '../configuration/configuration'
|
||||
|
||||
# Helper class for JSON Web Token (JWT) operations, including encoding and decoding.
|
||||
class JwtHelper
|
||||
@jwt_secret = ConfigurationManager.new.jwt_secret
|
||||
@token_use_for_request = ConfigurationManager.new.jwt_use_for_request
|
||||
|
||||
@jwt_secret = ConfigurationManager.new.jwt_secret
|
||||
@token_use_for_request = ConfigurationManager.new.jwt_use_for_request
|
||||
# check if a secret key to generate token exists or not
|
||||
def self.enabled?
|
||||
@jwt_secret.present?
|
||||
end
|
||||
|
||||
class << self
|
||||
# check if a secret key to generate token exists or not
|
||||
def is_enabled
|
||||
return @jwt_secret && !@jwt_secret.empty? ? true : false
|
||||
end
|
||||
# check if a secret key used for request
|
||||
def self.use_for_request
|
||||
@token_use_for_request
|
||||
end
|
||||
|
||||
# check if a secret key used for request
|
||||
def use_for_request
|
||||
return @token_use_for_request
|
||||
end
|
||||
# encode a payload object into a token using a secret key
|
||||
def self.encode(payload)
|
||||
JWT.encode(payload, @jwt_secret, 'HS256') # define the hashing algorithm and get token
|
||||
end
|
||||
|
||||
# encode a payload object into a token using a secret key
|
||||
def encode(payload)
|
||||
return JWT.encode payload, @jwt_secret, 'HS256' # define the hashing algorithm and get token
|
||||
end
|
||||
|
||||
# decode a token into a payload object using a secret key
|
||||
def decode(token)
|
||||
begin
|
||||
decoded = JWT.decode token, @jwt_secret, true, { algorithm: 'HS256' }
|
||||
rescue
|
||||
return ""
|
||||
end
|
||||
# decoded = Array [ {"data"=>"test"}, # payload
|
||||
# {"alg"=>"HS256"} # header ]
|
||||
return decoded[0].to_json # get json payload
|
||||
end
|
||||
# decode a token into a payload object using a secret key
|
||||
def self.decode(token)
|
||||
begin
|
||||
decoded = JWT.decode(token, @jwt_secret, true, { algorithm: 'HS256' })
|
||||
rescue StandardError
|
||||
return ''
|
||||
end
|
||||
end
|
||||
# decoded = Array [ {"data"=>"test"}, # payload
|
||||
# {"alg"=>"HS256"} # header ]
|
||||
decoded[0].to_json # get json payload
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -16,6 +18,7 @@
|
||||
|
||||
require_relative '../configuration/configuration'
|
||||
|
||||
# Class responsible for converting documents using a document conversion service.
|
||||
class ServiceConverter
|
||||
@config_manager = ConfigurationManager.new
|
||||
|
||||
@ -23,165 +26,151 @@ class ServiceConverter
|
||||
attr_reader :config_manager
|
||||
end
|
||||
|
||||
@@convert_timeout = ServiceConverter.config_manager.convertation_timeout
|
||||
@@document_converter_url = ServiceConverter.config_manager.document_server_converter_uri.to_s
|
||||
@convert_timeout = ServiceConverter.config_manager.convertation_timeout
|
||||
@document_converter_url = ServiceConverter.config_manager.document_server_converter_uri.to_s
|
||||
|
||||
class << self
|
||||
# get the url of the converted file
|
||||
def self.get_converted_data(document_uri, from_ext, to_ext, document_revision_id, is_async, file_pass, lang = nil)
|
||||
from_ext = File.extname(document_uri).downcase if from_ext.nil? # get the current document extension
|
||||
|
||||
# get the url of the converted file
|
||||
def get_converted_data(document_uri, from_ext, to_ext, document_revision_id, is_async, file_pass, lang = nil)
|
||||
# get the current document name or uuid
|
||||
title = File.basename(URI.parse(document_uri).path)
|
||||
title = UUID.generate.to_s if title.nil?
|
||||
|
||||
from_ext = from_ext == nil ? File.extname(document_uri).downcase : from_ext # get the current document extension
|
||||
# get the document key
|
||||
document_revision_id = document_uri if document_revision_id.empty?
|
||||
document_revision_id = generate_revision_id(document_revision_id)
|
||||
|
||||
# get the current document name or uuid
|
||||
title = File.basename(URI.parse(document_uri).path)
|
||||
title = title == nil ? UUID.generate.to_s : title
|
||||
payload = { # write all the conversion parameters to the payload
|
||||
async: is_async ? true : false,
|
||||
url: document_uri,
|
||||
outputtype: to_ext.delete('.'),
|
||||
filetype: from_ext.delete('.'),
|
||||
title:,
|
||||
key: document_revision_id,
|
||||
password: file_pass,
|
||||
region: lang
|
||||
}
|
||||
|
||||
# get the document key
|
||||
document_revision_id = document_revision_id.empty? ? document_uri : document_revision_id
|
||||
document_revision_id = generate_revision_id(document_revision_id)
|
||||
data = nil
|
||||
begin
|
||||
uri = URI.parse(@document_converter_url) # create the request url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
|
||||
payload = { # write all the conversion parameters to the payload
|
||||
:async => is_async ? true : false,
|
||||
:url => document_uri,
|
||||
:outputtype => to_ext.delete('.'),
|
||||
:filetype => from_ext.delete('.'),
|
||||
:title => title,
|
||||
:key => document_revision_id,
|
||||
:password => file_pass,
|
||||
:region => lang
|
||||
}
|
||||
DocumentHelper.verify_ssl(@document_converter_url, http)
|
||||
|
||||
data = nil
|
||||
begin
|
||||
http.read_timeout = @convert_timeout
|
||||
http.open_timeout = 5
|
||||
req = Net::HTTP::Post.new(uri.request_uri) # create the post request
|
||||
req.add_field('Accept', 'application/json') # set headers
|
||||
req.add_field('Content-Type', 'application/json')
|
||||
|
||||
uri = URI.parse(@@document_converter_url) # create the request url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
|
||||
DocumentHelper.verify_ssl(@@document_converter_url, http)
|
||||
|
||||
http.read_timeout = @@convert_timeout
|
||||
http.open_timeout = 5
|
||||
req = Net::HTTP::Post.new(uri.request_uri) # create the post request
|
||||
req.add_field("Accept", "application/json") # set headers
|
||||
req.add_field("Content-Type", "application/json")
|
||||
|
||||
if JwtHelper.is_enabled && JwtHelper.use_for_request # if the signature is enabled
|
||||
payload["token"] = JwtHelper.encode(payload) # get token and save it to the payload
|
||||
jwtHeader = ServiceConverter.config_manager.jwt_header; # get signature authorization header
|
||||
req.add_field(jwtHeader, "Bearer #{JwtHelper.encode({ :payload => payload })}") # set it to the request with the Bearer prefix
|
||||
end
|
||||
|
||||
req.body = payload.to_json
|
||||
res = http.request(req) # get the response
|
||||
|
||||
status_code = res.code.to_i
|
||||
if status_code != 200 # checking status code
|
||||
raise "Conversion service returned status: #{status_code}"
|
||||
end
|
||||
|
||||
data = res.body # and take its body
|
||||
rescue Timeout::Error
|
||||
# try again
|
||||
rescue => ex
|
||||
raise ex.message
|
||||
if JwtHelper.enabled? && JwtHelper.use_for_request # if the signature is enabled
|
||||
payload['token'] = JwtHelper.encode(payload) # get token and save it to the payload
|
||||
jwt_header = ServiceConverter.config_manager.jwt_header; # get signature authorization header
|
||||
# set it to the request with the Bearer prefix
|
||||
req.add_field(jwt_header, "Bearer #{JwtHelper.encode({ payload: })}")
|
||||
end
|
||||
|
||||
json_data = JSON.parse(data) # parse response body
|
||||
return get_response_data(json_data) # get response url
|
||||
end
|
||||
|
||||
# generate the document key value
|
||||
def generate_revision_id(expected_key)
|
||||
|
||||
require 'zlib'
|
||||
|
||||
if expected_key.length > 20 # check if the expected key length is greater than 20
|
||||
expected_key = (Zlib.crc32 expected_key).to_s # calculate 32-bit crc value from the expected key and turn it into the string
|
||||
end
|
||||
|
||||
key = expected_key.gsub(/[^0-9a-zA-Z.=]/, '_')
|
||||
key[(key.length - [key.length, 20].min)..key.length] # the resulting key is of the length 20 or less
|
||||
|
||||
end
|
||||
|
||||
# create an error message for the error code
|
||||
def process_convert_service_responce_error(error_code)
|
||||
|
||||
error_message = 'unknown error'
|
||||
|
||||
# add an error message to the error message template depending on the error code
|
||||
case error_code
|
||||
when -8
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error document VKey'
|
||||
when -7
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error document request'
|
||||
when -6
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error database'
|
||||
when -5
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Incorrect password'
|
||||
when -4
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error download error'
|
||||
when -3
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error convertation error'
|
||||
when -2
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error convertation timeout'
|
||||
when -1
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error convertation unknown'
|
||||
when 0
|
||||
# public const int c_nErrorNo = 0
|
||||
else
|
||||
error_message = 'ErrorCode = ' + error_code.to_s # default value for the error message
|
||||
end
|
||||
|
||||
raise error_message
|
||||
|
||||
end
|
||||
|
||||
# get the response url
|
||||
def get_response_data(json_data)
|
||||
|
||||
file_result = json_data
|
||||
|
||||
error_element = file_result['error']
|
||||
if error_element != nil # if an error occurs
|
||||
process_convert_service_responce_error(error_element.to_i) # get an error message
|
||||
end
|
||||
|
||||
is_end_convert = file_result['endConvert'] # check if the conversion is completed
|
||||
|
||||
result_percent = 0 # the conversion percentage
|
||||
response_uri = ''
|
||||
response_file_type = ''
|
||||
|
||||
if is_end_convert # if the conversion is completed
|
||||
|
||||
file_url_element = file_result['fileUrl']
|
||||
file_type_element = file_result['fileType']
|
||||
|
||||
if file_url_element == nil # and the file url doesn't exist
|
||||
raise 'Invalid answer format' # get ann error message
|
||||
end
|
||||
|
||||
response_uri = file_url_element # otherwise, get the file url
|
||||
response_file_type = file_type_element # get the file type
|
||||
result_percent = 100
|
||||
|
||||
else # if the conversion isn't completed
|
||||
|
||||
percent_element = file_result['percent'] # get the percentage value
|
||||
|
||||
if percent_element != nil
|
||||
result_percent = percent_element.to_i
|
||||
end
|
||||
|
||||
result_percent = result_percent >= 100 ? 99 : result_percent
|
||||
|
||||
end
|
||||
|
||||
return result_percent, response_uri, response_file_type
|
||||
req.body = payload.to_json
|
||||
res = http.request(req) # get the response
|
||||
|
||||
status_code = Integer(res.code, 10)
|
||||
raise("Conversion service returned status: #{status_code}") if status_code != 200 # checking status code
|
||||
|
||||
data = res.body # and take its body
|
||||
rescue Timeout::Error
|
||||
# try again
|
||||
rescue StandardError => e
|
||||
raise(e.message)
|
||||
end
|
||||
|
||||
json_data = JSON.parse(data) # parse response body
|
||||
get_response_data(json_data) # get response url
|
||||
end
|
||||
|
||||
end
|
||||
# generate the document key value
|
||||
def self.generate_revision_id(expected_key)
|
||||
require('zlib')
|
||||
|
||||
if expected_key.length > 20 # check if the expected key length is greater than 20
|
||||
# calculate 32-bit crc value from the expected key and turn it into the string
|
||||
expected_key = Zlib.crc32(expected_key).to_s
|
||||
end
|
||||
|
||||
key = expected_key.gsub(/[^0-9a-zA-Z.=]/, '_')
|
||||
key[(key.length - [key.length, 20].min)..key.length] # the resulting key is of the length 20 or less
|
||||
end
|
||||
|
||||
# create an error message for the error code
|
||||
def self.process_convert_service_responce_error(error_code)
|
||||
error_message = 'unknown error'
|
||||
|
||||
# add an error message to the error message template depending on the error code
|
||||
case error_code
|
||||
when -8
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error document VKey'
|
||||
when -7
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error document request'
|
||||
when -6
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error database'
|
||||
when -5
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Incorrect password'
|
||||
when -4
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error download error'
|
||||
when -3
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error convertation error'
|
||||
when -2
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error convertation timeout'
|
||||
when -1
|
||||
error_message = 'Error occurred in the ConvertService.ashx: Error convertation unknown'
|
||||
when 0
|
||||
# public const int c_nErrorNo = 0
|
||||
else
|
||||
error_message = "ErrorCode = #{error_code}" # default value for the error message
|
||||
end
|
||||
|
||||
raise(error_message)
|
||||
end
|
||||
|
||||
# get the response url
|
||||
def self.get_response_data(json_data)
|
||||
file_result = json_data
|
||||
|
||||
error_element = file_result['error']
|
||||
unless error_element.nil? # if an error occurs
|
||||
process_convert_service_responce_error(Integer(error_element, 10)) # get an error message
|
||||
end
|
||||
|
||||
is_end_convert = file_result['endConvert'] # check if the conversion is completed
|
||||
|
||||
result_percent = 0 # the conversion percentage
|
||||
response_uri = ''
|
||||
response_file_type = ''
|
||||
|
||||
if is_end_convert # if the conversion is completed
|
||||
|
||||
file_url_element = file_result['fileUrl']
|
||||
file_type_element = file_result['fileType']
|
||||
|
||||
if file_url_element.nil? # and the file url doesn't exist
|
||||
raise('Invalid answer format') # get ann error message
|
||||
end
|
||||
|
||||
response_uri = file_url_element # otherwise, get the file url
|
||||
response_file_type = file_type_element # get the file type
|
||||
result_percent = 100
|
||||
|
||||
else # if the conversion isn't completed
|
||||
|
||||
percent_element = file_result['percent'] # get the percentage value
|
||||
|
||||
result_percent = Integer(percent_element, 10) unless percent_element.nil?
|
||||
|
||||
result_percent = 99 if result_percent >= 100
|
||||
|
||||
end
|
||||
|
||||
[result_percent, response_uri, response_file_type]
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -19,6 +21,7 @@ require 'uri'
|
||||
require_relative '../configuration/configuration'
|
||||
require_relative '../proxy/proxy'
|
||||
|
||||
# Helper class for managing document tracking functionalities, such as saving and processing documents.
|
||||
class TrackHelper
|
||||
@config_manager = ConfigurationManager.new
|
||||
@proxy_manager = ProxyManager.new(config_manager: @config_manager)
|
||||
@ -28,307 +31,318 @@ class TrackHelper
|
||||
attr_reader :proxy_manager
|
||||
end
|
||||
|
||||
@@document_command_url = TrackHelper.config_manager.document_server_command_uri.to_s
|
||||
@document_command_url = TrackHelper.config_manager.document_server_command_uri.to_s
|
||||
|
||||
class << self
|
||||
# read the request body
|
||||
def self.read_body(request)
|
||||
body = request.body.read
|
||||
|
||||
# read the request body
|
||||
def read_body(request)
|
||||
body = request.body.read
|
||||
return '' if body.blank?
|
||||
|
||||
if body == nil || body.empty?
|
||||
return ""
|
||||
end
|
||||
file_data = JSON.parse(body) # parse file data
|
||||
|
||||
file_data = JSON.parse(body) # parse file data
|
||||
# check if a secret key to generate token exists or not
|
||||
if JwtHelper.enabled? && JwtHelper.use_for_request
|
||||
in_header = false
|
||||
token = nil
|
||||
jwt_header = TrackHelper.config_manager.jwt_header; # get the authorization header from the config
|
||||
if file_data['token'] # if the token is in the body
|
||||
token = JwtHelper.decode(file_data['token']) # decode a token into a payload object using a secret key
|
||||
elsif request.headers[jwt_header] # if the token is in the header
|
||||
hdr = request.headers[jwt_header]
|
||||
hdr.slice!(0, 'Bearer '.length) # get token from it (after Bearer prefix)
|
||||
token = JwtHelper.decode(hdr) # decode a token into a payload object using a secret key
|
||||
in_header = true
|
||||
else
|
||||
raise('Expected JWT') # token missing error message
|
||||
end
|
||||
|
||||
# check if a secret key to generate token exists or not
|
||||
if JwtHelper.is_enabled && JwtHelper.use_for_request
|
||||
inHeader = false
|
||||
token = nil
|
||||
jwtHeader = TrackHelper.config_manager.jwt_header; # get the authorization header from the config
|
||||
if file_data["token"] # if the token is in the body
|
||||
token = JwtHelper.decode(file_data["token"]) # decode a token into a payload object using a secret key
|
||||
elsif request.headers[jwtHeader] # if the token is in the header
|
||||
hdr = request.headers[jwtHeader]
|
||||
hdr.slice!(0, "Bearer ".length) # get token from it (after Bearer prefix)
|
||||
token = JwtHelper.decode(hdr) # decode a token into a payload object using a secret key
|
||||
inHeader = true
|
||||
else
|
||||
raise "Expected JWT" # token missing error message
|
||||
end
|
||||
raise('Invalid JWT signature') if !token || token.eql?('')
|
||||
|
||||
if !token || token.eql?("")
|
||||
raise "Invalid JWT signature"
|
||||
end
|
||||
file_data = JSON.parse(token)
|
||||
|
||||
file_data = JSON.parse(token)
|
||||
|
||||
if inHeader
|
||||
file_data = file_data["payload"]
|
||||
end
|
||||
end
|
||||
|
||||
return file_data
|
||||
end
|
||||
|
||||
def resolve_process_save_body(body)
|
||||
copied = body.dup
|
||||
|
||||
url = copied['url']
|
||||
if url
|
||||
uri = URI(url)
|
||||
resolved_uri = TrackHelper.proxy_manager.resolve_uri(uri)
|
||||
copied['url'] = resolved_uri.to_s
|
||||
end
|
||||
|
||||
changesurl = copied['changesurl']
|
||||
if changesurl
|
||||
uri = URI(changesurl)
|
||||
resolved_uri = TrackHelper.proxy_manager.resolve_uri(uri)
|
||||
copied['changesurl'] = resolved_uri.to_s
|
||||
end
|
||||
|
||||
home = copied['home']
|
||||
if home
|
||||
copied['home'] = resolve_process_save_body(home)
|
||||
end
|
||||
|
||||
copied
|
||||
end
|
||||
|
||||
# file saving process
|
||||
def process_save(raw_file_data, file_name, user_address)
|
||||
file_data = resolve_process_save_body(raw_file_data)
|
||||
|
||||
download_uri = file_data['url']
|
||||
if download_uri.eql?(nil)
|
||||
saved = 1
|
||||
return saved
|
||||
end
|
||||
|
||||
new_file_name = file_name
|
||||
download_ext = "."+file_data['filetype'] # get the extension of the downloaded file
|
||||
|
||||
cur_ext = File.extname(file_name).downcase # get current file extension
|
||||
|
||||
# convert downloaded file to the file with the current extension if these extensions aren't equal
|
||||
unless cur_ext.eql?(download_ext)
|
||||
key = ServiceConverter.generate_revision_id(download_uri) # get the document key
|
||||
begin
|
||||
percent, new_file_uri, new_file_type = ServiceConverter.get_converted_data(download_uri, download_ext.delete('.'), cur_ext.delete('.'), key, false, nil) # get the url of the converted file
|
||||
if new_file_uri == nil || new_file_uri.empty?
|
||||
new_file_name = DocumentHelper.get_correct_name(File.basename(file_name, cur_ext) + download_ext, user_address) # get the correct file name if it already exists
|
||||
else
|
||||
download_uri = new_file_uri
|
||||
end
|
||||
rescue StandardError => msg
|
||||
new_file_name = DocumentHelper.get_correct_name(File.basename(file_name, cur_ext) + download_ext, user_address)
|
||||
end
|
||||
end
|
||||
|
||||
saved = 1
|
||||
|
||||
data = download_file(download_uri) # download document file
|
||||
if data.eql?(nil)
|
||||
return saved
|
||||
end
|
||||
|
||||
begin
|
||||
storage_path = DocumentHelper.storage_path(new_file_name, user_address) # get the storage directory of the new file
|
||||
|
||||
hist_dir = DocumentHelper.history_dir(storage_path) # get the history directory of the new file
|
||||
ver_dir = DocumentHelper.version_dir(hist_dir, DocumentHelper.get_file_version(hist_dir)) # get the path to the specified file version
|
||||
|
||||
FileUtils.mkdir_p(ver_dir) # create the version directory if doesn't exist
|
||||
|
||||
FileUtils.move(DocumentHelper.storage_path(file_name, user_address), File.join(ver_dir, "prev#{cur_ext}")) # move the file from the storage directory to the previous file version directory
|
||||
|
||||
save_file(data, storage_path) # save the downloaded file to the storage directory
|
||||
|
||||
change_data = download_file(file_data["changesurl"]) # download file with document versions differences
|
||||
save_file(change_data, File.join(ver_dir, "diff.zip")) # save file with document versions differences
|
||||
|
||||
hist_data = file_data["changeshistory"]
|
||||
unless hist_data # if there are no changes in the history
|
||||
hist_data = file_data["history"].to_json # write the original history information to the history data
|
||||
end
|
||||
if hist_data
|
||||
File.open(File.join(ver_dir, "changes.json"), 'wb') do |file| # open the file with document changes
|
||||
file.write(hist_data) # and write history data to this file
|
||||
end
|
||||
end
|
||||
|
||||
# write the key value to the key.txt file
|
||||
File.open(File.join(ver_dir, "key.txt"), 'wb') do |file|
|
||||
file.write(file_data["key"])
|
||||
end
|
||||
|
||||
forcesave_path = DocumentHelper.forcesave_path(new_file_name, user_address, false) # get the path to the forcesaved file
|
||||
unless forcesave_path.eql?("") # if this path is empty
|
||||
File.delete(forcesave_path) # remove it
|
||||
end
|
||||
|
||||
saved = 0
|
||||
rescue StandardError => msg
|
||||
saved = 1
|
||||
end
|
||||
|
||||
saved
|
||||
end
|
||||
|
||||
# file force saving process
|
||||
def process_force_save(file_data, file_name, user_address)
|
||||
download_uri = file_data['url']
|
||||
if download_uri.eql?(nil)
|
||||
saved = 1
|
||||
return saved
|
||||
end
|
||||
|
||||
download_ext = "."+file_data['filetype'] # get the extension of the downloaded file
|
||||
|
||||
cur_ext = File.extname(file_name).downcase # get current file extension
|
||||
|
||||
new_file_name = false
|
||||
|
||||
# convert downloaded file to the file with the current extension if these extensions aren't equal
|
||||
unless cur_ext.eql?(download_ext)
|
||||
key = ServiceConverter.generate_revision_id(download_uri) # get the document key
|
||||
begin
|
||||
percent, new_file_uri, new_file_type = ServiceConverter.get_converted_data(download_uri, download_ext.delete('.'), cur_ext.delete('.'), key, false, nil) # get the url of the converted file
|
||||
if new_file_uri == nil || new_file_uri.empty?
|
||||
new_file_name = true
|
||||
else
|
||||
download_uri = new_file_uri
|
||||
end
|
||||
rescue StandardError => msg
|
||||
new_file_name = true
|
||||
end
|
||||
end
|
||||
|
||||
saved = 1
|
||||
|
||||
data = download_file(download_uri) # download document file
|
||||
if data.eql?(nil)
|
||||
return saved
|
||||
end
|
||||
|
||||
begin
|
||||
is_submit_form = file_data["forcesavetype"].to_i == 3 # check if the forcesave type is equal to 3 (the form was submitted)
|
||||
|
||||
if is_submit_form
|
||||
if new_file_name
|
||||
file_name = DocumentHelper.get_correct_name(File.basename(file_name, cur_ext) + "-form" + download_ext, user_address) # get the correct file name if it already exists
|
||||
else
|
||||
file_name = DocumentHelper.get_correct_name(File.basename(file_name, cur_ext) + "-form" + cur_ext, user_address)
|
||||
end
|
||||
forcesave_path = DocumentHelper.storage_path(file_name, user_address) # get the path to the new file
|
||||
else
|
||||
if new_file_name
|
||||
file_name = DocumentHelper.get_correct_name(File.basename(file_name, cur_ext) + download_ext, user_address)
|
||||
end
|
||||
forcesave_path = DocumentHelper.forcesave_path(file_name, user_address, false)
|
||||
if forcesave_path.eql?("")
|
||||
forcesave_path = DocumentHelper.forcesave_path(file_name, user_address, true) # if the path to the new file doesn't exist, create it
|
||||
end
|
||||
end
|
||||
|
||||
save_file(data, forcesave_path) # save the downloaded file to the storage directory
|
||||
|
||||
if is_submit_form
|
||||
uid = file_data['actions'][0]['userid']
|
||||
DocumentHelper.create_meta(file_name, uid, "Filling Form", user_address) # create file meta information with the Filling form tag instead of user name
|
||||
|
||||
forms_data_url = file_data["formsdataurl"].to_s
|
||||
|
||||
if forms_data_url && !forms_data_url.eql?("")
|
||||
forms_name = DocumentHelper.get_correct_name(File.basename(file_name, cur_ext) + ".txt", user_address)
|
||||
forms_path = DocumentHelper.storage_path(forms_name, user_address)
|
||||
forms = download_file(forms_data_url)
|
||||
if forms.eql?(nil)
|
||||
return saved
|
||||
end
|
||||
save_file(forms, forms_path)
|
||||
else
|
||||
raise 'Document editing service did not return formsDataUrl'
|
||||
end
|
||||
end
|
||||
|
||||
saved = 0
|
||||
rescue StandardError => msg
|
||||
saved = 1
|
||||
end
|
||||
|
||||
saved
|
||||
end
|
||||
|
||||
# send the command request
|
||||
def command_request(method, key, meta = nil)
|
||||
# create a payload object with the method and key
|
||||
payload = {
|
||||
:c => method,
|
||||
:key => key
|
||||
}
|
||||
|
||||
if (meta != nil)
|
||||
payload.merge!({:meta => meta})
|
||||
end
|
||||
|
||||
data = nil
|
||||
begin
|
||||
|
||||
uri = URI.parse(@@document_command_url) # parse the document command url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
|
||||
DocumentHelper.verify_ssl(@@document_command_url, http)
|
||||
|
||||
req = Net::HTTP::Post.new(uri.request_uri) # create the post request
|
||||
req.add_field("Content-Type", "application/json") # set headers
|
||||
|
||||
if JwtHelper.is_enabled && JwtHelper.use_for_request # if the signature is enabled
|
||||
payload["token"] = JwtHelper.encode(payload) # get token and save it to the payload
|
||||
jwtHeader = TrackHelper.config_manager.jwt_header; # get signature authorization header
|
||||
req.add_field(jwtHeader, "Bearer #{JwtHelper.encode({ :payload => payload })}") # set it to the request with the Bearer prefix
|
||||
end
|
||||
|
||||
req.body = payload.to_json # convert the payload object into the json format
|
||||
res = http.request(req) # get the response
|
||||
data = res.body # and take its body
|
||||
rescue => ex
|
||||
raise ex.message
|
||||
end
|
||||
|
||||
json_data = JSON.parse(data) # convert the response body into the json format
|
||||
return json_data
|
||||
end
|
||||
|
||||
# save file from the url
|
||||
def download_file(uristr)
|
||||
uri = URI.parse(uristr) # parse the url string
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
http.open_timeout = 5
|
||||
|
||||
DocumentHelper.verify_ssl(uristr, http)
|
||||
|
||||
req = Net::HTTP::Get.new(uri)
|
||||
res = http.request(req) # get the response
|
||||
|
||||
status_code = res.code
|
||||
if status_code != '200' # checking status code
|
||||
raise "Document editing service returned status: #{status_code}"
|
||||
end
|
||||
data = res.body # and take its body
|
||||
|
||||
if data == nil
|
||||
raise 'stream is null'
|
||||
end
|
||||
data
|
||||
end
|
||||
|
||||
def save_file(data, path)
|
||||
File.open(path, 'wb') do |file| # open the file from the path specified
|
||||
file.write(data) # and write the response data to it
|
||||
end
|
||||
end
|
||||
file_data = file_data['payload'] if in_header
|
||||
end
|
||||
end
|
||||
|
||||
file_data
|
||||
end
|
||||
|
||||
def self.resolve_process_save_body(body)
|
||||
copied = body.dup
|
||||
|
||||
url = copied['url']
|
||||
if url
|
||||
uri = URI(url)
|
||||
resolved_uri = TrackHelper.proxy_manager.resolve_uri(uri)
|
||||
copied['url'] = resolved_uri.to_s
|
||||
end
|
||||
|
||||
changesurl = copied['changesurl']
|
||||
if changesurl
|
||||
uri = URI(changesurl)
|
||||
resolved_uri = TrackHelper.proxy_manager.resolve_uri(uri)
|
||||
copied['changesurl'] = resolved_uri.to_s
|
||||
end
|
||||
|
||||
home = copied['home']
|
||||
copied['home'] = resolve_process_save_body(home) if home
|
||||
|
||||
copied
|
||||
end
|
||||
|
||||
# file saving process
|
||||
def self.process_save(raw_file_data, file_name, user_address)
|
||||
file_data = resolve_process_save_body(raw_file_data)
|
||||
|
||||
download_uri = file_data['url']
|
||||
if download_uri.eql?(nil)
|
||||
saved = 1
|
||||
return saved
|
||||
end
|
||||
|
||||
new_file_name = file_name
|
||||
download_ext = ".#{file_data['filetype']}" # get the extension of the downloaded file
|
||||
|
||||
cur_ext = File.extname(file_name).downcase # get current file extension
|
||||
|
||||
# convert downloaded file to the file with the current extension if these extensions aren't equal
|
||||
unless cur_ext.eql?(download_ext)
|
||||
key = ServiceConverter.generate_revision_id(download_uri) # get the document key
|
||||
begin
|
||||
_, new_file_uri, = ServiceConverter.get_converted_data(
|
||||
download_uri,
|
||||
download_ext.delete('.'),
|
||||
cur_ext.delete('.'),
|
||||
key,
|
||||
false,
|
||||
nil
|
||||
) # get the url of the converted file
|
||||
if new_file_uri.blank?
|
||||
new_file_name = DocumentHelper.get_correct_name(
|
||||
File.basename(file_name, cur_ext) + download_ext,
|
||||
user_address
|
||||
) # get the correct file name if it already exists
|
||||
else
|
||||
download_uri = new_file_uri
|
||||
end
|
||||
rescue StandardError
|
||||
new_file_name = DocumentHelper.get_correct_name(
|
||||
File.basename(file_name, cur_ext) + download_ext,
|
||||
user_address
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
saved = 1
|
||||
|
||||
data = download_file(download_uri) # download document file
|
||||
return saved if data.eql?(nil)
|
||||
|
||||
begin
|
||||
# get the storage directory of the new file
|
||||
storage_path = DocumentHelper.storage_path(new_file_name, user_address)
|
||||
|
||||
hist_dir = DocumentHelper.history_dir(storage_path) # get the history directory of the new file
|
||||
# get the path to the specified file version
|
||||
ver_dir = DocumentHelper.version_dir(hist_dir, DocumentHelper.get_file_version(hist_dir))
|
||||
|
||||
FileUtils.mkdir_p(ver_dir) # create the version directory if doesn't exist
|
||||
|
||||
# move the file from the storage directory to the previous file version directory
|
||||
FileUtils.move(DocumentHelper.storage_path(file_name, user_address), File.join(ver_dir, "prev#{cur_ext}"))
|
||||
|
||||
save_file(data, storage_path) # save the downloaded file to the storage directory
|
||||
|
||||
change_data = download_file(file_data['changesurl']) # download file with document versions differences
|
||||
save_file(change_data, File.join(ver_dir, 'diff.zip')) # save file with document versions differences
|
||||
|
||||
hist_data = file_data['changeshistory']
|
||||
hist_data ||= file_data['history'].to_json
|
||||
if hist_data
|
||||
File.binwrite(File.join(ver_dir, 'changes.json'), hist_data)
|
||||
end
|
||||
|
||||
# write the key value to the key.txt file
|
||||
File.binwrite(File.join(ver_dir, 'key.txt'), file_data['key'])
|
||||
|
||||
# get the path to the forcesaved file
|
||||
forcesave_path = DocumentHelper.forcesave_path(new_file_name, user_address, false)
|
||||
unless forcesave_path.eql?('') # if this path is empty
|
||||
File.delete(forcesave_path) # remove it
|
||||
end
|
||||
|
||||
saved = 0
|
||||
rescue StandardError
|
||||
saved = 1
|
||||
end
|
||||
|
||||
saved
|
||||
end
|
||||
|
||||
# file force saving process
|
||||
def self.process_force_save(file_data, file_name, user_address)
|
||||
download_uri = file_data['url']
|
||||
if download_uri.eql?(nil)
|
||||
saved = 1
|
||||
return saved
|
||||
end
|
||||
|
||||
download_ext = ".#{file_data['filetype']}" # get the extension of the downloaded file
|
||||
|
||||
cur_ext = File.extname(file_name).downcase # get current file extension
|
||||
|
||||
new_file_name = false
|
||||
|
||||
# convert downloaded file to the file with the current extension if these extensions aren't equal
|
||||
unless cur_ext.eql?(download_ext)
|
||||
key = ServiceConverter.generate_revision_id(download_uri) # get the document key
|
||||
begin
|
||||
_, new_file_uri, = ServiceConverter.get_converted_data(
|
||||
download_uri,
|
||||
download_ext.delete('.'),
|
||||
cur_ext.delete('.'),
|
||||
key,
|
||||
false,
|
||||
nil
|
||||
) # get the url of the converted file
|
||||
if new_file_uri.blank?
|
||||
new_file_name = true
|
||||
else
|
||||
download_uri = new_file_uri
|
||||
end
|
||||
rescue StandardError
|
||||
new_file_name = true
|
||||
end
|
||||
end
|
||||
|
||||
saved = 1
|
||||
|
||||
data = download_file(download_uri) # download document file
|
||||
return saved if data.eql?(nil)
|
||||
|
||||
begin
|
||||
# check if the forcesave type is equal to 3 (the form was submitted)
|
||||
is_submit_form = Integer(file_data['forcesavetype'], 10) == 3
|
||||
|
||||
if is_submit_form
|
||||
file_name = if new_file_name
|
||||
DocumentHelper.get_correct_name(
|
||||
"#{File.basename(file_name, cur_ext)}-form#{download_ext}",
|
||||
user_address
|
||||
) # get the correct file name if it already exists
|
||||
else
|
||||
DocumentHelper.get_correct_name(
|
||||
"#{File.basename(file_name, cur_ext)}-form#{cur_ext}",
|
||||
user_address
|
||||
)
|
||||
end
|
||||
forcesave_path = DocumentHelper.storage_path(file_name, user_address) # get the path to the new file
|
||||
else
|
||||
if new_file_name
|
||||
file_name = DocumentHelper.get_correct_name(
|
||||
File.basename(file_name, cur_ext) + download_ext,
|
||||
user_address
|
||||
)
|
||||
end
|
||||
forcesave_path = DocumentHelper.forcesave_path(file_name, user_address, false)
|
||||
if forcesave_path.eql?('')
|
||||
# if the path to the new file doesn't exist, create it
|
||||
forcesave_path = DocumentHelper.forcesave_path(file_name, user_address, true)
|
||||
end
|
||||
end
|
||||
|
||||
save_file(data, forcesave_path) # save the downloaded file to the storage directory
|
||||
|
||||
if is_submit_form
|
||||
uid = file_data['actions'][0]['userid']
|
||||
# create file meta information with the Filling form tag instead of user name
|
||||
DocumentHelper.create_meta(file_name, uid, 'Filling Form', user_address)
|
||||
|
||||
forms_data_url = file_data['formsdataurl'].to_s
|
||||
|
||||
unless forms_data_url && !forms_data_url.eql?('')
|
||||
raise('Document editing service did not return formsDataUrl')
|
||||
end
|
||||
forms_name = DocumentHelper.get_correct_name(
|
||||
"#{File.basename(file_name, cur_ext)}.txt",
|
||||
user_address
|
||||
)
|
||||
forms_path = DocumentHelper.storage_path(forms_name, user_address)
|
||||
forms = download_file(forms_data_url)
|
||||
if forms.eql?(nil)
|
||||
return saved
|
||||
end
|
||||
save_file(forms, forms_path)
|
||||
|
||||
end
|
||||
|
||||
saved = 0
|
||||
rescue StandardError
|
||||
saved = 1
|
||||
end
|
||||
|
||||
saved
|
||||
end
|
||||
|
||||
# send the command request
|
||||
def self.command_request(method, key, meta = nil)
|
||||
# create a payload object with the method and key
|
||||
payload = {
|
||||
c: method,
|
||||
key:
|
||||
}
|
||||
|
||||
payload.merge!({ meta: }) unless meta.nil?
|
||||
|
||||
data = nil
|
||||
begin
|
||||
uri = URI.parse(@document_command_url) # parse the document command url
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
|
||||
DocumentHelper.verify_ssl(@document_command_url, http)
|
||||
|
||||
req = Net::HTTP::Post.new(uri.request_uri) # create the post request
|
||||
req.add_field('Content-Type', 'application/json') # set headers
|
||||
|
||||
if JwtHelper.enabled? && JwtHelper.use_for_request # if the signature is enabled
|
||||
payload['token'] = JwtHelper.encode(payload) # get token and save it to the payload
|
||||
jwt_header = TrackHelper.config_manager.jwt_header; # get signature authorization header
|
||||
# set it to the request with the Bearer prefix
|
||||
req.add_field(jwt_header, "Bearer #{JwtHelper.encode({ payload: })}")
|
||||
end
|
||||
|
||||
req.body = payload.to_json # convert the payload object into the json format
|
||||
res = http.request(req) # get the response
|
||||
data = res.body # and take its body
|
||||
rescue StandardError => e
|
||||
raise(e.message)
|
||||
end
|
||||
|
||||
JSON.parse(data) # convert the response body into the json format
|
||||
end
|
||||
|
||||
# save file from the url
|
||||
def self.download_file(uristr)
|
||||
uri = URI.parse(uristr) # parse the url string
|
||||
http = Net::HTTP.new(uri.host, uri.port) # create a connection to the http server
|
||||
http.open_timeout = 5
|
||||
|
||||
DocumentHelper.verify_ssl(uristr, http)
|
||||
|
||||
req = Net::HTTP::Get.new(uri)
|
||||
res = http.request(req) # get the response
|
||||
|
||||
status_code = res.code
|
||||
raise("Document editing service returned status: #{status_code}") if status_code != '200' # checking status code
|
||||
|
||||
data = res.body # and take its body
|
||||
|
||||
raise('stream is null') if data.nil?
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
def self.save_file(data, path)
|
||||
File.binwrite(path, data)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#
|
||||
# (c) Copyright Ascensio System SIA 2023
|
||||
#
|
||||
@ -14,139 +16,201 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Represents a user with various attributes
|
||||
class User
|
||||
attr_accessor :id, :name, :email, :group, :reviewGroups, :commentGroups, :userInfoGroups, :favorite,
|
||||
:deniedPermissions, :descriptions, :templates, :avatar
|
||||
attr_accessor :id
|
||||
attr_accessor :name
|
||||
attr_accessor :email
|
||||
attr_accessor :group
|
||||
attr_accessor :review_groups
|
||||
attr_accessor :comment_groups
|
||||
attr_accessor :user_info_groups
|
||||
attr_accessor :favorite
|
||||
attr_accessor :denied_permissions
|
||||
attr_accessor :descriptions
|
||||
attr_accessor :templates
|
||||
attr_accessor :avatar
|
||||
|
||||
def initialize (id, name, email, group, reviewGroups, commentGroups, userInfoGroups, favorite,
|
||||
deniedPermissions, descriptions, templates, avatar)
|
||||
@id = id
|
||||
@name = name
|
||||
@email = email
|
||||
@group = group
|
||||
@reviewGroups = reviewGroups
|
||||
@commentGroups = commentGroups
|
||||
@favorite = favorite
|
||||
@deniedPermissions = deniedPermissions
|
||||
@descriptions = descriptions
|
||||
@templates = templates
|
||||
@userInfoGroups = userInfoGroups
|
||||
@avatar = avatar
|
||||
end
|
||||
def initialize(
|
||||
id,
|
||||
name,
|
||||
email,
|
||||
group,
|
||||
review_groups,
|
||||
comment_groups,
|
||||
user_info_groups,
|
||||
favorite,
|
||||
denied_permissions,
|
||||
descriptions,
|
||||
templates,
|
||||
avatar
|
||||
)
|
||||
@id = id
|
||||
@name = name
|
||||
@email = email
|
||||
@group = group
|
||||
@review_groups = review_groups
|
||||
@comment_groups = comment_groups
|
||||
@favorite = favorite
|
||||
@denied_permissions = denied_permissions
|
||||
@descriptions = descriptions
|
||||
@templates = templates
|
||||
@user_info_groups = user_info_groups
|
||||
@avatar = avatar
|
||||
end
|
||||
end
|
||||
|
||||
# Manages user-related data and operations.
|
||||
class Users
|
||||
@@descr_user_1 = [
|
||||
"File author by default",
|
||||
"Doesn’t belong to any group",
|
||||
"Can review all the changes",
|
||||
"Can perform all actions with comments",
|
||||
"The file favorite state is undefined",
|
||||
"Can create files from templates using data from the editor",
|
||||
"Can see the information about all users",
|
||||
"Has an avatar",
|
||||
"Can submit forms",
|
||||
];
|
||||
@descr_user_first = [
|
||||
'File author by default',
|
||||
'Doesn’t belong to any group',
|
||||
'Can review all the changes',
|
||||
'Can perform all actions with comments',
|
||||
'The file favorite state is undefined',
|
||||
'Can create files from templates using data from the editor',
|
||||
'Can see the information about all users',
|
||||
'Has an avatar',
|
||||
'Can submit forms'
|
||||
]
|
||||
|
||||
@@descr_user_2 = [
|
||||
"Belongs to Group2",
|
||||
"Can review only his own changes or changes made by users with no group",
|
||||
"Can view comments, edit his own comments and comments left by users with no group. Can remove his own comments only",
|
||||
"This file is marked as favorite",
|
||||
"Can create new files from the editor",
|
||||
"Can see the information about users from Group2 and users who don’t belong to any group",
|
||||
"Has an avatar",
|
||||
"Can't submit forms",
|
||||
];
|
||||
@descr_user_second = [
|
||||
'Belongs to Group2',
|
||||
'Can review only his own changes or changes made by users with no group',
|
||||
'Can view comments, edit his own comments, and comments left by users with no group. ' \
|
||||
'Can remove his own comments only',
|
||||
'This file is marked as favorite',
|
||||
'Can create new files from the editor',
|
||||
'Can see the information about users from Group2 and users who don’t belong to any group',
|
||||
'Has an avatar',
|
||||
'Can’t submit forms'
|
||||
]
|
||||
|
||||
@@descr_user_3 = [
|
||||
"Belongs to Group3",
|
||||
"Can review changes made by Group2 users",
|
||||
"Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users",
|
||||
"This file isn’t marked as favorite",
|
||||
"Can’t copy data from the file to clipboard",
|
||||
"Can’t download the file",
|
||||
"Can’t print the file",
|
||||
"Can create new files from the editor",
|
||||
"Can see the information about Group2 users",
|
||||
"Can't submit forms",
|
||||
];
|
||||
@descr_user_third = [
|
||||
'Belongs to Group3',
|
||||
'Can review changes made by Group2 users',
|
||||
'Can view comments left by Group2 and Group3 users. Can edit comments left by the Group2 users',
|
||||
'This file isn’t marked as favorite',
|
||||
'Can’t copy data from the file to clipboard',
|
||||
'Can’t download the file',
|
||||
'Can’t print the file',
|
||||
'Can create new files from the editor',
|
||||
'Can see the information about Group2 users',
|
||||
'Can’t submit forms'
|
||||
]
|
||||
|
||||
@@descr_user_0 = [
|
||||
"The name is requested when the editor is opened",
|
||||
"Doesn’t belong to any group",
|
||||
"Can review all the changes",
|
||||
"Can perform all actions with comments",
|
||||
"The file favorite state is undefined",
|
||||
"Can't mention others in comments",
|
||||
"Can't create new files from the editor",
|
||||
"Can’t see anyone’s information",
|
||||
"Can't rename files from the editor",
|
||||
"Can't view chat",
|
||||
"Can't protect file",
|
||||
"View file without collaboration",
|
||||
"Can't submit forms"
|
||||
];
|
||||
@descr_user_null = [
|
||||
'The name is requested when the editor is opened',
|
||||
'Doesn’t belong to any group',
|
||||
'Can review all the changes',
|
||||
'Can perform all actions with comments',
|
||||
'The file favorite state is undefined',
|
||||
"Can't mention others in comments",
|
||||
"Can't create new files from the editor",
|
||||
'Can’t see anyone’s information',
|
||||
"Can't rename files from the editor",
|
||||
"Can't view chat",
|
||||
"Can't protect file",
|
||||
'View file without collaboration',
|
||||
'Can’t submit forms'
|
||||
]
|
||||
|
||||
@@users = [
|
||||
User.new("uid-1", "John Smith", "smith@example.com",
|
||||
"", nil, {}, nil,
|
||||
nil, [], @@descr_user_1, true, true),
|
||||
User.new("uid-2", "Mark Pottato", "pottato@example.com",
|
||||
"group-2", ["group-2", ""], {
|
||||
:view => "",
|
||||
:edit => ["group-2", ""],
|
||||
:remove => ["group-2"]
|
||||
},
|
||||
["group-2", ""],
|
||||
true, [], @@descr_user_2, false, true),
|
||||
User.new("uid-3", "Hamish Mitchell", nil,
|
||||
"group-3", ["group-2"], {
|
||||
:view => ["group-3", "group-2"],
|
||||
:edit => ["group-2"],
|
||||
:remove => []
|
||||
},
|
||||
["group-2"],
|
||||
false, ["copy", "download", "print"], @@descr_user_3, false, false),
|
||||
User.new("uid-0", nil, nil,
|
||||
"", nil, {}, [],
|
||||
nil, ["protect"], @@descr_user_0, false, false)
|
||||
]
|
||||
@users = [
|
||||
User.new(
|
||||
'uid-1',
|
||||
'John Smith',
|
||||
'smith@example.com',
|
||||
'',
|
||||
nil,
|
||||
{},
|
||||
nil,
|
||||
nil,
|
||||
[],
|
||||
@descr_user_first,
|
||||
true,
|
||||
true
|
||||
),
|
||||
User.new(
|
||||
'uid-2',
|
||||
'Mark Pottato',
|
||||
'pottato@example.com',
|
||||
'group-2',
|
||||
['group-2', ''],
|
||||
{
|
||||
view: '',
|
||||
edit: ['group-2', ''],
|
||||
remove: ['group-2']
|
||||
},
|
||||
['group-2', ''],
|
||||
true,
|
||||
[],
|
||||
@descr_user_second,
|
||||
false,
|
||||
true
|
||||
),
|
||||
User.new(
|
||||
'uid-3',
|
||||
'Hamish Mitchell',
|
||||
nil,
|
||||
'group-3',
|
||||
['group-2'],
|
||||
{
|
||||
view: ['group-3', 'group-2'],
|
||||
edit: ['group-2'],
|
||||
remove: []
|
||||
},
|
||||
['group-2'],
|
||||
false,
|
||||
['copy', 'download', 'print'],
|
||||
@descr_user_third,
|
||||
false,
|
||||
false
|
||||
),
|
||||
User.new(
|
||||
'uid-0',
|
||||
nil,
|
||||
nil,
|
||||
'',
|
||||
nil,
|
||||
{},
|
||||
[],
|
||||
nil,
|
||||
['protect'],
|
||||
@descr_user_null,
|
||||
false,
|
||||
false
|
||||
)
|
||||
]
|
||||
|
||||
class << self
|
||||
def get_all_users() # get a list of all the users
|
||||
@@users
|
||||
end
|
||||
|
||||
def get_user(id) # get a user by id specified
|
||||
for user in @@users do
|
||||
if user.id.eql?(id)
|
||||
return user
|
||||
end
|
||||
end
|
||||
return @@users[0]
|
||||
end
|
||||
|
||||
def get_users_for_mentions(id) # get a list of users with their names and emails for mentions
|
||||
usersData = []
|
||||
for user in @@users do
|
||||
if (!user.id.eql?(id) && user.name != nil && user.email != nil)
|
||||
usersData.push({:name => user.name, :email => user.email})
|
||||
end
|
||||
end
|
||||
return usersData
|
||||
end
|
||||
|
||||
def get_users_for_protect(id) # get a list of users with their id, names and emails for protect
|
||||
users_data = []
|
||||
for user in @@users do
|
||||
if (!user.id.eql?(id) && user.name != nil)
|
||||
users_data.push({id: user.id, name: user.name, email: user.email})
|
||||
end
|
||||
end
|
||||
return users_data
|
||||
end
|
||||
def self.all_users
|
||||
@users
|
||||
end
|
||||
|
||||
# get a user by id specified
|
||||
def self.get_user(id)
|
||||
@users.each do |user|
|
||||
return user if user.id.eql?(id)
|
||||
end
|
||||
end
|
||||
@users[0]
|
||||
end
|
||||
|
||||
# get a list of users with their names and emails for mentions
|
||||
def self.get_users_for_mentions(id)
|
||||
users_data = []
|
||||
@users.each do |user|
|
||||
if !user.id.eql?(id) && !user.name.nil? && !user.email.nil?
|
||||
users_data.push({ name: user.name, email: user.email })
|
||||
end
|
||||
end
|
||||
users_data
|
||||
end
|
||||
|
||||
# get a list of users with their id, names and emails for protect
|
||||
def self.get_users_for_protect(id)
|
||||
users_data = []
|
||||
@users.each do |user|
|
||||
users_data.push({ id: user.id, name: user.name, email: user.email }) if !user.id.eql?(id) && !user.name.nil?
|
||||
end
|
||||
users_data
|
||||
end
|
||||
end
|
||||
|
||||
@ -21,6 +21,7 @@ require 'sorbet-runtime'
|
||||
require 'uri'
|
||||
require_relative '../configuration/configuration'
|
||||
|
||||
# Class manages URI resolution, redirecting public URLs to private ones based on the configuration.
|
||||
class ProxyManager
|
||||
extend T::Sig
|
||||
|
||||
@ -32,21 +33,20 @@ class ProxyManager
|
||||
sig { params(uri: URI::Generic).returns(URI::Generic) }
|
||||
def resolve_uri(uri)
|
||||
return uri unless refer_public_url(uri)
|
||||
|
||||
redirect_public_url(uri)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { params(uri: URI::Generic).returns(T::Boolean) }
|
||||
def refer_public_url(uri)
|
||||
private def refer_public_url(uri)
|
||||
public_uri = @config_manager.document_server_public_uri
|
||||
uri.scheme == public_uri.scheme &&
|
||||
uri.host == public_uri.host &&
|
||||
uri.port == public_uri.port
|
||||
uri.host == public_uri.host &&
|
||||
uri.port == public_uri.port
|
||||
end
|
||||
|
||||
sig { params(uri: URI::Generic).returns(URI::Generic) }
|
||||
def redirect_public_url(uri)
|
||||
private def redirect_public_url(uri)
|
||||
private_uri = @config_manager.document_server_private_uri
|
||||
redirected_uri = uri
|
||||
redirected_uri.scheme = private_uri.scheme
|
||||
|
||||
@ -20,7 +20,9 @@
|
||||
require 'test/unit'
|
||||
require_relative 'proxy'
|
||||
|
||||
# Test case for ProxyManager resolving URIs that refer to public and non-public URLs.
|
||||
class ProxyManagerRefersTests < Test::Unit::TestCase
|
||||
# Mocked configuration manager for testing.
|
||||
class MockedConfigurationManager < ConfigurationManager
|
||||
def document_server_public_uri
|
||||
URI('http://localhost')
|
||||
@ -31,6 +33,7 @@ class ProxyManagerRefersTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case to ensure resolving a URI that refers to the public URI.
|
||||
def test_resolves_a_uri_that_refers_to_the_public_uri
|
||||
config_manager = MockedConfigurationManager.new
|
||||
proxy_manager = ProxyManager.new(config_manager:)
|
||||
@ -43,13 +46,16 @@ class ProxyManagerRefersTests < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
# Test case for ProxyManager resolving a URL that does not refer to the public URL.
|
||||
class ProxyManagerDoesNotRefersTests < Test::Unit::TestCase
|
||||
# Mocked configuration manager for testing.
|
||||
class MockedConfigurationManager < ConfigurationManager
|
||||
def document_server_public_uri
|
||||
URI('http://localhost')
|
||||
end
|
||||
end
|
||||
|
||||
# Test case to ensure resolving a URL that does not refer to the public URL.
|
||||
def test_resolves_a_url_that_does_not_refers_to_the_public_url
|
||||
config_manager = MockedConfigurationManager.new
|
||||
proxy_manager = ProxyManager.new(config_manager:)
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
var docEditor;
|
||||
var config;
|
||||
var versionHistory;
|
||||
|
||||
var innerAlert = function (message, inEditor) {
|
||||
if (console && console.log)
|
||||
@ -102,20 +103,20 @@
|
||||
var onRequestInsertImage = function(event) {
|
||||
docEditor.insertImage({ // insert an image into the file
|
||||
"c": event.data.c,
|
||||
<%= raw @file.get_insert_image %>
|
||||
<%= raw @file.insert_image %>
|
||||
})
|
||||
};
|
||||
|
||||
// the user is trying to select document for comparing by clicking the Document from Storage button
|
||||
var onRequestSelectDocument = function(event) {
|
||||
var data = <%= raw @file.dataDocument.to_json %>;
|
||||
var data = <%= raw @file.data_document.to_json %>;
|
||||
data.c = event.data.c;
|
||||
docEditor.setRequestedDocument(data); // select a document for comparing
|
||||
};
|
||||
|
||||
// the user is trying to select recipients data by clicking the Mail merge button
|
||||
var onRequestSelectSpreadsheet = function (event) {
|
||||
var data = <%= raw @file.dataSpreadsheet.to_json %>;
|
||||
var data = <%= raw @file.data_spreadsheet.to_json %>;
|
||||
data.c = event.data.c;
|
||||
docEditor.setRequestedSpreadsheet(data); // insert recipient data for mail merge into the file
|
||||
};
|
||||
@ -210,13 +211,34 @@
|
||||
innerAlert(response.error)
|
||||
return
|
||||
}
|
||||
document.location.reload();
|
||||
onRequestHistory()
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestHistory() {
|
||||
fileData = <%= raw @file.to_json %>;
|
||||
const req = new XMLHttpRequest()
|
||||
req.open("POST", '/historyobj')
|
||||
req.send(JSON.stringify(fileData))
|
||||
req.onload = function () {
|
||||
versionHistory = JSON.parse(req.response)
|
||||
docEditor.refreshHistory(versionHistory.hist)
|
||||
}
|
||||
}
|
||||
|
||||
function onRequestHistoryData(event){
|
||||
var ver = event.data;
|
||||
var histData = versionHistory.histData;
|
||||
docEditor.setHistoryData(histData[ver - 1]);
|
||||
}
|
||||
|
||||
function onRequestHistoryClose(){
|
||||
document.location.reload();
|
||||
}
|
||||
|
||||
var сonnectEditor = function () {
|
||||
|
||||
config = <%= raw @file.get_config.to_json %>;
|
||||
config = <%= raw @file.config.to_json %>;
|
||||
|
||||
config.width = "100%";
|
||||
config.height = "100%";
|
||||
@ -230,30 +252,16 @@
|
||||
'onRequestInsertImage': onRequestInsertImage,
|
||||
'onRequestSelectDocument': onRequestSelectDocument,
|
||||
'onRequestSelectSpreadsheet': onRequestSelectSpreadsheet,
|
||||
'onRequestRestore': onRequestRestore
|
||||
'onRequestRestore': onRequestRestore,
|
||||
'onRequestHistory': onRequestHistory,
|
||||
'onRequestHistoryData': onRequestHistoryData,
|
||||
'onRequestHistoryClose': onRequestHistoryClose
|
||||
};
|
||||
|
||||
<%
|
||||
history = @file.get_history
|
||||
usersMentions = @file.get_users_mentions %>
|
||||
usersMentions = @file.users_mentions %>
|
||||
|
||||
if (config.editorConfig.user.id) {
|
||||
<% if history %>
|
||||
// the user is trying to show the document version history
|
||||
config.events['onRequestHistory'] = function () {
|
||||
docEditor.refreshHistory(<%= raw history[:hist].to_json %>); // show the document version history
|
||||
};
|
||||
// the user is trying to click the specific document version in the document version history
|
||||
config.events['onRequestHistoryData'] = function (event) {
|
||||
var ver = event.data;
|
||||
var histData = <%= raw history[:histData].to_json %>;
|
||||
docEditor.setHistoryData(histData[ver - 1]); // send the link to the document for viewing the version history
|
||||
};
|
||||
// the user is trying to go back to the document from viewing the document version history
|
||||
config.events['onRequestHistoryClose'] = function () {
|
||||
document.location.reload();
|
||||
};
|
||||
<% end %>
|
||||
// add mentions for not anonymous users
|
||||
config.events['onRequestUsers'] = function (event) {
|
||||
if (event && event.data){
|
||||
@ -262,7 +270,7 @@
|
||||
switch (c) {
|
||||
case "info":
|
||||
users = [];
|
||||
var allUsers = <%= raw @file.get_users_info.to_json %>;
|
||||
var allUsers = <%= raw @file.users_info.to_json %>;
|
||||
for (var i = 0; i < event.data.id.length; i++) {
|
||||
for (var j = 0; j < allUsers.length; j++) {
|
||||
if (allUsers[j].id == event.data.id[i]) {
|
||||
@ -273,10 +281,10 @@
|
||||
}
|
||||
break;
|
||||
case "protect":
|
||||
var users = <%= raw @file.get_users_protect.to_json %>;
|
||||
var users = <%= raw @file.users_protect.to_json %>;
|
||||
break;
|
||||
default:
|
||||
users = <%= raw @file.get_users_mentions.to_json %>;
|
||||
users = <%= raw @file.users_mentions.to_json %>;
|
||||
}
|
||||
docEditor.setUsers({
|
||||
"c": c,
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
<span class="select-user">Username</span>
|
||||
<img id="info" class="info" data-id="user" src="assets/info.svg" />
|
||||
<select class="select-user" id="user">
|
||||
<% for user in Users.get_all_users() do %>
|
||||
<% for user in Users.all_users() do %>
|
||||
<option value="<%= user.id %>"><%= user.name ? user.name : "Anonymous" %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
@ -110,7 +110,7 @@
|
||||
</span>
|
||||
<span class="portal-descr">Please do NOT use this integration example on your own server without proper code modifications, it is intended for testing purposes only. In case you enabled this test example, disable it before going for production.</span>
|
||||
<span class="portal-descr">You can open the same document using different users in different Web browser sessions, so you can check out multi-user editing functions.</span>
|
||||
<% for user in Users.get_all_users() do %>
|
||||
<% for user in Users.all_users() do %>
|
||||
<div class="user-descr">
|
||||
<b><%= user.name ? user.name : "Anonymous" %></b>
|
||||
<ul>
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="server-version" content="<%= ConfigurationManager.new.version %>" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'config/application'
|
||||
|
||||
Rails.application.initialize!
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'boot'
|
||||
|
||||
require 'active_model/railtie'
|
||||
@ -9,11 +11,12 @@ Bundler.require(*Rails.groups)
|
||||
|
||||
require 'securerandom'
|
||||
|
||||
# Configuration for the Rails application.
|
||||
class Application < Rails::Application
|
||||
config.middleware.insert_before 0, Rack::Cors do
|
||||
config.middleware.insert_before(0, Rack::Cors) do
|
||||
allow do
|
||||
origins '*'
|
||||
resource '*', headers: :any, methods: %i[get post patch delete put options]
|
||||
resource '*', headers: :any, methods: [:get, :post, :patch, :delete, :put, :options]
|
||||
end
|
||||
end
|
||||
|
||||
@ -31,6 +34,7 @@ class Application < Rails::Application
|
||||
match '/asset', to: 'home#assets', via: 'get'
|
||||
match '/download', to: 'home#download', via: 'get'
|
||||
match '/downloadhistory', to: 'home#downloadhistory', via: 'get'
|
||||
match '/historyobj', to: 'home#historyobj', via: 'post'
|
||||
match '/editor', to: 'home#editor', via: 'get'
|
||||
match '/files', to: 'home#files', via: 'get'
|
||||
match '/index', to: 'home#index', via: 'get'
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
||||
|
||||
require 'bundler/setup'
|
||||
|
||||
Reference in New Issue
Block a user