Compare commits

...

10 Commits

23 changed files with 172 additions and 24 deletions

2
.gitmodules vendored
View File

@ -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

View File

@ -1,6 +1,9 @@
# Change Log
- nodejs: pdf, djvu, xps, oxps as pdf documentType
- nodejs: filling pdf
- version number to page meta
- ar skin languages
- sr-Latn-CS skin languages
- getting history via api
- using a repo with a list of formats

View File

@ -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|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.languages" value="en:English|ar:Arabic|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/"/>

View File

@ -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|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.languages" value="en:English|ar:Arabic|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/"/>

View File

@ -10,4 +10,5 @@
<suppress checks="JavadocPackage" files="."/>
<suppress checks="JavadocVariable" files="."/>
<suppress checks="MissingJavadocMethod" files="."/>
<suppress checks="MagicNumber" files="DefaultDocumentManager.java"/>
</suppressions>

View File

@ -20,11 +20,14 @@ package com.onlyoffice.integration.documentserver.managers.document;
import com.onlyoffice.integration.documentserver.storage.FileStorageMutator;
import com.onlyoffice.integration.documentserver.storage.FileStoragePathBuilder;
import com.onlyoffice.integration.documentserver.util.Constants;
import com.onlyoffice.integration.documentserver.util.file.FileUtility;
import com.onlyoffice.integration.documentserver.util.service.ServiceConverter;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import java.io.File;
@ -243,4 +246,58 @@ public class DefaultDocumentManager implements DocumentManager {
return fileName;
}
@SneakyThrows
public Boolean isExtendedPDFFile(final String fileName) {
Resource resource = storageMutator.loadFileAsResource(fileName);
byte[] bytes;
try (InputStream inputStream = resource.getInputStream()) {
bytes = inputStream.readNBytes(110);
} catch (Exception e) {
return false;
}
String pBuffer = new String(bytes, "Windows-1252");
int indexFirst = pBuffer.indexOf("%\315\312\322\251\015");
if (indexFirst == -1) {
return false;
}
String pFirst = pBuffer.substring(indexFirst + 6);
if (!pFirst.startsWith("1 0 obj\012<<\012")) {
return false;
}
pFirst = pFirst.substring(11);
int indexStream = pFirst.indexOf("stream\015\012");
int indexMeta = pFirst.indexOf(Constants.G_FORMAT_OFORM_PDF_META_TAG);
if (indexStream == -1 || indexMeta == -1 || indexStream < indexMeta) {
return false;
}
String pMeta = pFirst.substring(indexMeta);
pMeta = pMeta.substring(Constants.G_FORMAT_OFORM_PDF_META_TAG.length() + 3);
int indexMetaLast = pMeta.indexOf(" ");
if (indexMetaLast == -1) {
return false;
}
pMeta = pMeta.substring(indexMetaLast + 1);
indexMetaLast = pMeta.indexOf(" ");
if (indexMetaLast == -1) {
return false;
}
return true;
}
}

View File

@ -39,4 +39,5 @@ public interface DocumentManager {
// create demo document
String createDemo(String fileExt, Boolean sample, String uid, String uname) throws Exception;
String getCreateUrl(String fileName, Boolean sample); // get URL to the created file
Boolean isExtendedPDFFile(String fileName);
}

View File

@ -27,6 +27,7 @@ public final class Constants {
public static final Integer MAX_KEY_LENGTH = 20;
public static final Integer ANONYMOUS_USER_ID = 4;
public static final Integer KILOBYTE_SIZE = 1024;
public static final String G_FORMAT_OFORM_PDF_META_TAG = "ONLYOFFICEFORM";
private Constants() { }
}

View File

@ -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|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.languages=en:English|ar:Arabic|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

View File

@ -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|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.languages=en:English|ar:Arabic|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

View File

@ -936,18 +936,21 @@ app.get('/editor', (req, res) => { // define a handler for editing document
const templatesImageUrl = req.DocManager.getTemplateImageUrl(fileUtility.getFileType(fileName));
const createUrl = req.DocManager.getCreateUrl(fileUtility.getFileType(fileName), userid, type, lang);
const templates = [
{
image: '',
title: 'Blank',
url: createUrl,
},
{
image: templatesImageUrl,
title: 'With sample content',
url: `${createUrl}&sample=true`,
},
];
let templates = null;
if (createUrl != null) {
templates = [
{
image: '',
title: 'Blank',
url: createUrl,
},
{
image: templatesImageUrl,
title: 'With sample content',
url: `${createUrl}&sample=true`,
},
];
}
const userGroup = user.group;
const { reviewGroups } = user;
@ -994,19 +997,30 @@ app.get('/editor', (req, res) => { // define a handler for editing document
if (!canEdit && mode === 'edit') {
mode = 'view';
}
const submitForm = mode === 'fillForms' && userid === 'uid-1';
const ext = fileUtility.getFileExtension(fileName, true);
let isForm = 'null';
if (req.query.checkform !== 'false' && ext === 'pdf') {
isForm = req.DocManager.isExtendedPDFFile(fileName);
}
let submitForm = false;
if (mode === 'fillForms') {
submitForm = userid === 'uid-1';
}
// 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,

View File

@ -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,
@ -39,6 +40,7 @@
"verify_peer_off": true,
"languages": {
"en": "English",
"ar": "Arabic",
"hy": "Armenian",
"az": "Azerbaijani",
"eu": "Basque",

View File

@ -214,7 +214,11 @@ DocManager.prototype.getCallback = function getCallback(fileName) {
// get url to the created file
DocManager.prototype.getCreateUrl = function getCreateUrl(docType, userid, type, lang) {
const server = this.getServerUrl();
const ext = this.getInternalExtension(docType).replace('.', '');
let ext = this.getInternalExtension(docType);
if (ext === null) {
return null;
}
ext = ext.replace('.', '');
const handler = `/editor?fileExt=${ext}&userid=${userid}&type=${type}&lang=${lang}`;
return server + handler;
@ -381,7 +385,7 @@ DocManager.prototype.getInternalExtension = function getInternalExtension(fileTy
return '.pptx';
}
return '.docx'; // the default value is .docx
return null; // the default value is null
};
// get the template image url
@ -606,6 +610,59 @@ 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);
fileSystem.closeSync(fd);
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();
};

View File

@ -64,6 +64,7 @@ fileUtility.fileType = {
word: 'word',
cell: 'cell',
slide: 'slide',
pdf: 'pdf',
};
fileUtility.getSuppotredExtensions = function getSuppotredExtensions() {

View File

@ -145,7 +145,8 @@ const getDefaultAction = async function getDefaultAction(ext) {
// get the action url
const getActionUrl = function getActionUrl(host, userAddress, action, filename) {
return `${action.urlsrc.replace(/<.*&>/g, '')}WOPISrc=${host}/wopi/files/${filename}@${userAddress}`;
const WOPISrc = `${host}/wopi/files/${filename}@${userAddress}`;
return `${action.urlsrc.replace(/<.*&>/g, '')}WOPISrc=${encodeURIComponent(WOPISrc)}`;
};
exports.initWopi = initWopi;

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -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;

View File

@ -6,6 +6,7 @@
"uploaded": "<%- file.created %>",
"favorite": <%- file.favorite %>
},
"isForm": <%- file.isForm %>,
"key": "<%- editor.key %>",
"permissions": {
"chat": <%- editor.chat %>,

View File

@ -163,7 +163,8 @@ class ConfigurationManager
public function languages(): array
{
return [
'en' => "English",
'en' => 'English',
'ar' => 'Arabic',
'hy' => 'Armenian',
'az' => 'Azerbaijani',
'eu' => 'Basque',

View File

@ -124,6 +124,7 @@ class ConfigurationManager:
def languages(self) -> dict[str, str]:
return {
'en': 'English',
'ar': 'Arabic',
'hy': 'Armenian',
'az': 'Azerbaijani',
'eu': 'Basque',

View File

@ -142,6 +142,7 @@ class ConfigurationManager
def languages
{
en: 'English',
ar: 'Arabic',
hy: 'Armenian',
az: 'Azerbaijani',
eu: 'Basque',