From 380927307547e6c291d3ce49e061e6819174383e Mon Sep 17 00:00:00 2001 From: AlexeySafronov Date: Fri, 12 Nov 2021 15:19:40 +0300 Subject: [PATCH 001/395] bump version to 1.1.0 --- lerna.json | 2 +- packages/asc-web-common/package.json | 2 +- packages/asc-web-components/package.json | 2 +- packages/browserslist-config-asc/package.json | 2 +- packages/debug-info/package.json | 2 +- products/ASC.CRM/Client/package.json | 2 +- products/ASC.Calendar/Client/package.json | 2 +- products/ASC.Files/Client/package.json | 2 +- products/ASC.Mail/Client/package.json | 2 +- products/ASC.People/Client/package.json | 2 +- products/ASC.Projects/Client/package.json | 2 +- web/ASC.Web.Client/package.json | 2 +- web/ASC.Web.Editor/package.json | 2 +- web/ASC.Web.Login/package.json | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lerna.json b/lerna.json index 5ef065cbbf2..60d8c002566 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "1.0.0", + "version": "1.1.0", "npmClient": "yarn", "packages": [ "packages/asc-web-components", diff --git a/packages/asc-web-common/package.json b/packages/asc-web-common/package.json index 6d3f4958a1b..d56a42c5b09 100644 --- a/packages/asc-web-common/package.json +++ b/packages/asc-web-common/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/common", - "version": "1.0.0", + "version": "1.1.0", "private": true, "scripts": { "build": "echo 'skip it'", diff --git a/packages/asc-web-components/package.json b/packages/asc-web-components/package.json index d2d3fec2586..eed68ec5bde 100644 --- a/packages/asc-web-components/package.json +++ b/packages/asc-web-components/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/components", - "version": "1.0.0", + "version": "1.1.0", "private": true, "scripts": { "build": "echo 'skip it'", diff --git a/packages/browserslist-config-asc/package.json b/packages/browserslist-config-asc/package.json index 369daa62a5b..13737faf104 100644 --- a/packages/browserslist-config-asc/package.json +++ b/packages/browserslist-config-asc/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/browserslist-config-asc", - "version": "1.0.0", + "version": "1.1.0", "description": "Shared browserslist for AppServer libraries and apps", "main": "browserlist.config.js", "scripts": { diff --git a/packages/debug-info/package.json b/packages/debug-info/package.json index 86acc6550ab..a41d873940e 100644 --- a/packages/debug-info/package.json +++ b/packages/debug-info/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/debug-info", - "version": "1.0.0", + "version": "1.1.0", "private": true, "description": "Command line tool for generating debug info by commit history", "main": "src/index.js", diff --git a/products/ASC.CRM/Client/package.json b/products/ASC.CRM/Client/package.json index 583f5c158d4..4959641a955 100644 --- a/products/ASC.CRM/Client/package.json +++ b/products/ASC.CRM/Client/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/crm", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/products/crm", "scripts": { diff --git a/products/ASC.Calendar/Client/package.json b/products/ASC.Calendar/Client/package.json index 526e573c514..abca21941bb 100644 --- a/products/ASC.Calendar/Client/package.json +++ b/products/ASC.Calendar/Client/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/calendar", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/products/calendar", "scripts": { diff --git a/products/ASC.Files/Client/package.json b/products/ASC.Files/Client/package.json index 1f6fab5a944..36ba1b7763a 100644 --- a/products/ASC.Files/Client/package.json +++ b/products/ASC.Files/Client/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/files", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/products/files", "scripts": { diff --git a/products/ASC.Mail/Client/package.json b/products/ASC.Mail/Client/package.json index 52396c44e9e..e09f102faaa 100644 --- a/products/ASC.Mail/Client/package.json +++ b/products/ASC.Mail/Client/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/mail", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/products/mail", "scripts": { diff --git a/products/ASC.People/Client/package.json b/products/ASC.People/Client/package.json index 3e3d6b25b3d..21b09f3de7a 100644 --- a/products/ASC.People/Client/package.json +++ b/products/ASC.People/Client/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/people", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/products/people", "scripts": { diff --git a/products/ASC.Projects/Client/package.json b/products/ASC.Projects/Client/package.json index e05588bfe68..3d6a0b74221 100644 --- a/products/ASC.Projects/Client/package.json +++ b/products/ASC.Projects/Client/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/projects", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/products/projects", "scripts": { diff --git a/web/ASC.Web.Client/package.json b/web/ASC.Web.Client/package.json index 2396676221a..47e565d237f 100644 --- a/web/ASC.Web.Client/package.json +++ b/web/ASC.Web.Client/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/studio", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "", "scripts": { diff --git a/web/ASC.Web.Editor/package.json b/web/ASC.Web.Editor/package.json index ae0045726c5..cf6417efd8a 100644 --- a/web/ASC.Web.Editor/package.json +++ b/web/ASC.Web.Editor/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/editor", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/products/files/doceditor", "scripts": { diff --git a/web/ASC.Web.Login/package.json b/web/ASC.Web.Login/package.json index f4cb7d7bbe9..e8d813c67fd 100644 --- a/web/ASC.Web.Login/package.json +++ b/web/ASC.Web.Login/package.json @@ -1,6 +1,6 @@ { "name": "@appserver/login", - "version": "1.0.0", + "version": "1.1.0", "private": true, "homepage": "/login", "scripts": { From 4af7032a9aa460e3c9a7b1467fb42dbf888cd99e Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Tue, 16 Nov 2021 16:40:27 +0300 Subject: [PATCH 002/395] Web: Files: Added blank actions for form file. Added form action icons. Added en translation key`s for action buttons. --- .../Client/public/images/form.file.react.svg | 3 +++ .../Client/public/images/form.react.svg | 3 +++ .../Client/public/locales/en/Article.json | 6 ++++-- .../src/components/Article/MainButton/index.js | 17 +++++++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 products/ASC.Files/Client/public/images/form.file.react.svg create mode 100644 products/ASC.Files/Client/public/images/form.react.svg diff --git a/products/ASC.Files/Client/public/images/form.file.react.svg b/products/ASC.Files/Client/public/images/form.file.react.svg new file mode 100644 index 00000000000..c570b642bf5 --- /dev/null +++ b/products/ASC.Files/Client/public/images/form.file.react.svg @@ -0,0 +1,3 @@ + + + diff --git a/products/ASC.Files/Client/public/images/form.react.svg b/products/ASC.Files/Client/public/images/form.react.svg new file mode 100644 index 00000000000..611c4298445 --- /dev/null +++ b/products/ASC.Files/Client/public/images/form.react.svg @@ -0,0 +1,3 @@ + + + diff --git a/products/ASC.Files/Client/public/locales/en/Article.json b/products/ASC.Files/Client/public/locales/en/Article.json index 52f49986880..dc992935529 100644 --- a/products/ASC.Files/Client/public/locales/en/Article.json +++ b/products/ASC.Files/Client/public/locales/en/Article.json @@ -4,5 +4,7 @@ "NewPresentation": "New Presentation", "NewSpreadsheet": "New Spreadsheet", "UploadFiles": "Upload files", - "UploadFolder": "Upload folder" -} \ No newline at end of file + "UploadFolder": "Upload folder", + "NewForm": "New form", + "NewFormFile": "New form from file" +} diff --git a/products/ASC.Files/Client/src/components/Article/MainButton/index.js b/products/ASC.Files/Client/src/components/Article/MainButton/index.js index cd952f2540a..bec1807875a 100644 --- a/products/ASC.Files/Client/src/components/Article/MainButton/index.js +++ b/products/ASC.Files/Client/src/components/Article/MainButton/index.js @@ -24,6 +24,10 @@ class ArticleMainButtonContent extends React.Component { }); }; + onSelectFile = () => { + console.log("Select from form"); + }; + onUploadFileClick = () => { if (this.props.isPrivacy) { encryptionUploadDialog((encryptedFile, encrypted) => { @@ -101,6 +105,19 @@ class ArticleMainButtonContent extends React.Component { onClick={this.onCreate} data-format="pptx" /> + + Date: Tue, 16 Nov 2021 18:23:39 +0300 Subject: [PATCH 003/395] Web: Components: add avatar max size label --- packages/asc-web-components/avatar-editor/index.js | 3 +++ .../sub-components/avatar-editor-body.js | 14 +++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/asc-web-components/avatar-editor/index.js b/packages/asc-web-components/avatar-editor/index.js index 5447358c930..f675240a004 100644 --- a/packages/asc-web-components/avatar-editor/index.js +++ b/packages/asc-web-components/avatar-editor/index.js @@ -131,6 +131,7 @@ class AvatarEditor extends React.Component { saveButtonLoading, useModalDialog, cancelButtonLabel, + maxSizeLabel, } = this.props; return useModalDialog ? ( @@ -165,6 +166,7 @@ class AvatarEditor extends React.Component { unknownTypeError={unknownTypeError} maxSizeFileError={maxSizeFileError} unknownError={unknownError} + maxSizeLabel={maxSizeLabel} /> @@ -271,6 +273,7 @@ AvatarEditor.propTypes = { style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), /** Use for the view of the modal dialog or not */ useModalDialog: PropTypes.bool, + maxSizeLabel: PropTypes.string, }; AvatarEditor.defaultProps = { diff --git a/packages/asc-web-components/avatar-editor/sub-components/avatar-editor-body.js b/packages/asc-web-components/avatar-editor/sub-components/avatar-editor-body.js index 8648565a7e3..f6f59adb4a7 100644 --- a/packages/asc-web-components/avatar-editor/sub-components/avatar-editor-body.js +++ b/packages/asc-web-components/avatar-editor/sub-components/avatar-editor-body.js @@ -326,7 +326,14 @@ class AvatarEditorBody extends React.Component { }; render() { - const { maxSize, accept, role, title, useModalDialog } = this.props; + const { + maxSize, + accept, + role, + title, + useModalDialog, + maxSizeLabel, + } = this.props; const desktopMode = isDesktop(); //const tabletMode = isTablet(); @@ -483,6 +490,10 @@ class AvatarEditorBody extends React.Component { )} + + {maxSizeLabel} + + {this.state.errorText !== null && ( @@ -514,6 +525,7 @@ AvatarEditorBody.propTypes = { role: PropTypes.string, title: PropTypes.string, useModalDialog: PropTypes.bool, + maxSizeLabel: PropTypes.string, }; AvatarEditorBody.defaultProps = { From e0f297bf0a16321abcde9b2c636105085b295f56 Mon Sep 17 00:00:00 2001 From: Viktor Fomin Date: Tue, 16 Nov 2021 18:24:02 +0300 Subject: [PATCH 004/395] Web: People: add translations --- products/ASC.People/Client/public/locales/de/Translations.json | 3 ++- products/ASC.People/Client/public/locales/en/Translations.json | 3 ++- products/ASC.People/Client/public/locales/ru/Translations.json | 3 ++- .../Client/src/pages/Profile/Section/Header/index.js | 1 + .../src/pages/ProfileAction/Section/Body/avatarEditorPage.js | 1 + .../pages/ProfileAction/Section/Body/createAvatarEditorPage.js | 1 + .../src/pages/ProfileAction/Section/Body/createUserForm.js | 1 + .../src/pages/ProfileAction/Section/Body/updateUserForm.js | 1 + 8 files changed, 11 insertions(+), 3 deletions(-) diff --git a/products/ASC.People/Client/public/locales/de/Translations.json b/products/ASC.People/Client/public/locales/de/Translations.json index 3dd1dbf4f1c..26cc6eb8d1d 100644 --- a/products/ASC.People/Client/public/locales/de/Translations.json +++ b/products/ASC.People/Client/public/locales/de/Translations.json @@ -25,5 +25,6 @@ "SocialProfiles": "Soziale Profile", "SuccessChangeUserStatus": "Der Benutzerstatus war erfolgreich geändert", "SuccessSentInvitation": "Die Einladung wurde erfolgreich gesendet", - "Birthdate": "Geburtsdatum" + "Birthdate": "Geburtsdatum", + "maxSizeLabel": "(JPG oder PNG, maximal 1 MB)" } diff --git a/products/ASC.People/Client/public/locales/en/Translations.json b/products/ASC.People/Client/public/locales/en/Translations.json index a6fd9c6b203..eb69f667701 100644 --- a/products/ASC.People/Client/public/locales/en/Translations.json +++ b/products/ASC.People/Client/public/locales/en/Translations.json @@ -26,5 +26,6 @@ "SuccessChangeUserStatus": "The user status was successfully changed", "SuccessSentInvitation": "The invitation was successfully sent", "SuccessDeletePersonalData": "Personal data has been successfully deleted", - "Birthdate": "Date of birth" + "Birthdate": "Date of birth", + "maxSizeLabel": "(JPG or PNG, max 1 MB)" } diff --git a/products/ASC.People/Client/public/locales/ru/Translations.json b/products/ASC.People/Client/public/locales/ru/Translations.json index 00c37976d20..c908dfd8131 100644 --- a/products/ASC.People/Client/public/locales/ru/Translations.json +++ b/products/ASC.People/Client/public/locales/ru/Translations.json @@ -26,5 +26,6 @@ "SuccessChangeUserStatus": "Статус пользователя успешно изменен", "SuccessSentInvitation": "Приглашение было успешно отправлено", "SuccessDeletePersonalData": "Персональные данные успешно удалены", - "Birthdate": "Дата рождения" + "Birthdate": "Дата рождения", + "maxSizeLabel": "(JPG или PNG, максимум 1 Мб)" } diff --git a/products/ASC.People/Client/src/pages/Profile/Section/Header/index.js b/products/ASC.People/Client/src/pages/Profile/Section/Header/index.js index a038ab85a6f..b638cd0db3e 100644 --- a/products/ASC.People/Client/src/pages/Profile/Section/Header/index.js +++ b/products/ASC.People/Client/src/pages/Profile/Section/Header/index.js @@ -476,6 +476,7 @@ class SectionHeaderContent extends React.PureComponent { maxSizeFileError={t("Translations:maxSizeFileError")} unknownError={t("Common:Error")} saveButtonLabel={t("Common:SaveButton")} + maxSizeLabel={t("Translations:maxSizeLabel")} /> {dialogsVisible.deleteSelfProfile && ( diff --git a/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/avatarEditorPage.js b/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/avatarEditorPage.js index b81b5a28e63..5e8c8a3f81c 100644 --- a/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/avatarEditorPage.js +++ b/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/avatarEditorPage.js @@ -304,6 +304,7 @@ class AvatarEditorPage extends React.PureComponent { } cancelButtonLabel={t("Common:CancelButton")} saveButtonLoading={this.state.isLoading} + maxSizeLabel={t("Translations:maxSizeLabel")} /> ) : ( diff --git a/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createAvatarEditorPage.js b/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createAvatarEditorPage.js index 1c3a02ec2a8..a83c84c3bd0 100644 --- a/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createAvatarEditorPage.js +++ b/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createAvatarEditorPage.js @@ -267,6 +267,7 @@ class CreateAvatarEditorPage extends React.PureComponent { } cancelButtonLabel={t("Common:CancelButton")} saveButtonLoading={this.state.isLoading} + maxSizeLabel={t("Translations:maxSizeLabel")} /> ) : ( diff --git a/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createUserForm.js b/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createUserForm.js index f96233ad15c..6dc3dd9058a 100644 --- a/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createUserForm.js +++ b/products/ASC.People/Client/src/pages/ProfileAction/Section/Body/createUserForm.js @@ -489,6 +489,7 @@ class CreateUserForm extends React.Component { maxSizeFileError={t("Translations:maxSizeFileError")} unknownError={t("Common:Error")} saveButtonLabel={t("Common:SaveButton")} + maxSizeLabel={t("Translations:maxSizeLabel")} /> Date: Tue, 16 Nov 2021 20:40:15 +0300 Subject: [PATCH 005/395] moved from 043e301 --- common/ASC.Common/Web/MimeMapping.cs | 9 +- .../Billing/License/License.cs | 11 +- .../Caching/CachedTenantService.cs | 6 +- .../Caching/CachedUserService.cs | 8 +- .../Context/Impl/TenantManager.cs | 6 +- common/ASC.Core.Common/Core/ITenantService.cs | 4 +- common/ASC.Core.Common/Core/IUserService.cs | 4 +- .../ASC.Core.Common/Data/DbTenantService.cs | 11 +- common/ASC.Core.Common/Data/DbUserService.cs | 8 + common/ASC.Core.Common/HostedSolution.cs | 5 +- .../Controllers/PeopleController.cs | 140 ++++++++++++++ config/appsettings.json | 14 +- .../Core/Core/Dao/Interfaces/IDaoFactory.cs | 4 +- .../Core/Core/Dao/Interfaces/ILinkDao.cs | 31 +++ .../Core/Core/Dao/TeamlabDao/DaoFactory.cs | 7 + .../Core/Core/Dao/TeamlabDao/FileDao.cs | 60 +++--- .../Core/Core/Dao/TeamlabDao/LinkDao.cs | 116 ++++++++++++ .../Core/Core/Dao/TeamlabDao/TagDao.cs | 14 +- .../ASC.Files/Core/Core/EF/DbFilesLink.cs | 98 ++++++++++ .../ASC.Files/Core/Core/EF/FilesDbContext.cs | 7 +- products/ASC.Files/Core/Core/Entries/File.cs | 22 ++- .../ASC.Files/Core/Core/Entries/FileEntry.cs | 11 +- .../ASC.Files/Core/Core/FileStorageService.cs | 86 +++++++-- .../Core/Core/Security/FileSecurity.cs | 158 +++++++++------- .../Core/Core/Thirdparty/Box/BoxFileDao.cs | 10 +- .../Core/Core/Thirdparty/Box/BoxFolderDao.cs | 10 +- .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 12 +- .../Thirdparty/Dropbox/DropboxFolderDao.cs | 14 +- .../GoogleDrive/GoogleDriveFileDao.cs | 10 +- .../GoogleDrive/GoogleDriveFolderDao.cs | 12 +- .../GoogleDrive/GoogleDriveStorage.cs | 4 +- .../Thirdparty/OneDrive/OneDriveFileDao.cs | 10 +- .../Thirdparty/OneDrive/OneDriveFolderDao.cs | 12 +- .../Thirdparty/ProviderDao/ProviderDaoBase.cs | 2 +- .../SharePoint/SharePointFolderDao.cs | 10 +- .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 10 +- .../Thirdparty/Sharpbox/SharpBoxFolderDao.cs | 10 +- .../HttpHandlers/ChunkedUploaderHandler.cs | 6 +- .../Core/HttpHandlers/FileHandler.ashx.cs | 8 +- .../Core/Model/CheckFillFormDraftModel.cs | 26 +++ .../ASC.Files/Core/Model/PrivacyRoomModel.cs | 1 + .../Resources/FilesCommonResource.Designer.cs | 38 +++- .../Core/Resources/FilesCommonResource.resx | 75 +++++++- .../Services/DocumentService/Configuration.cs | 10 +- .../DocumentServiceConnector.cs | 52 ++--- .../DocumentService/DocumentServiceTracker.cs | 2 +- .../FileOperations/FileDeleteOperation.cs | 4 +- .../FileOperations/FileMoveCopyOperation.cs | 15 +- .../FileOperations/FileOperation.cs | 7 +- products/ASC.Files/Core/Utils/EntryManager.cs | 111 ++++++++++- .../ASC.Files/Core/Utils/FileConverter.cs | 6 +- products/ASC.Files/Core/Utils/FileUploader.cs | 10 +- .../Server/Controllers/FilesController.cs | 36 +++- .../Controllers/PrivacyRoomController.cs | 10 +- .../Server/Helpers/FilesControllerHelper.cs | 5 + .../ASC.Files/Service/Thumbnail/Builder.cs | 4 +- .../Service/Thumbnail/ThumbnailSettings.cs | 2 +- .../Controllers/AuthenticationController.cs | 5 + .../Controllers/PortalController.cs | 24 ++- .../Controllers/SettingsController.cs | 12 +- web/ASC.Web.Api/Models/QuotaWrapper.cs | 4 +- web/ASC.Web.Core/Files/DocumentService.cs | 179 ++++++++++++++---- .../Files/DocumentServiceLicense.cs | 97 ++++++++++ web/ASC.Web.Core/Files/FileUtility.cs | 4 +- .../Notify/StudioNotifyService.cs | 10 +- .../Notify/StudioNotifyServiceSender.cs | 5 +- .../Notify/StudioPeriodicNotify.cs | 4 +- web/ASC.Web.Core/SetupInfo.cs | 11 +- .../WhiteLabel/CompanyWhiteLabelSettings.cs | 10 +- 69 files changed, 1431 insertions(+), 328 deletions(-) create mode 100644 common/services/ASC.ApiSystem/Controllers/PeopleController.cs create mode 100644 products/ASC.Files/Core/Core/Dao/Interfaces/ILinkDao.cs create mode 100644 products/ASC.Files/Core/Core/Dao/TeamlabDao/LinkDao.cs create mode 100644 products/ASC.Files/Core/Core/EF/DbFilesLink.cs create mode 100644 products/ASC.Files/Core/Model/CheckFillFormDraftModel.cs create mode 100644 web/ASC.Web.Core/Files/DocumentServiceLicense.cs diff --git a/common/ASC.Common/Web/MimeMapping.cs b/common/ASC.Common/Web/MimeMapping.cs index e3cdf33aa06..f7bdd493b13 100644 --- a/common/ASC.Common/Web/MimeMapping.cs +++ b/common/ASC.Common/Web/MimeMapping.cs @@ -158,7 +158,8 @@ static MimeMapping() AddMimeMapping(".doc", "application/msword"); AddMimeMapping(".docm", "application/vnd.ms-word.document.macroEnabled.12"); AddMimeMapping(".doct", "application/doct"); - AddMimeMapping(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + AddMimeMapping(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); + AddMimeMapping(".docxf", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); AddMimeMapping(".dot", "application/msword"); AddMimeMapping(".dotm", "application/vnd.ms-word.template.macroEnabled.12"); AddMimeMapping(".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template"); @@ -429,7 +430,8 @@ static MimeMapping() AddMimeMapping(".oda", "application/oda"); AddMimeMapping(".odp", "application/vnd.oasis.opendocument.presentation"); AddMimeMapping(".ods", "application/vnd.oasis.opendocument.spreadsheet"); - AddMimeMapping(".odt", "application/vnd.oasis.opendocument.text"); + AddMimeMapping(".odt", "application/vnd.oasis.opendocument.text"); + AddMimeMapping(".oform", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); AddMimeMapping(".oga", "audio/ogg"); AddMimeMapping(".ogg", "video/ogg"); AddMimeMapping(".ogg", "audio/ogg"); @@ -710,7 +712,8 @@ static MimeMapping() AddMimeMapping(".wml", "text/vnd.wap.wml"); AddMimeMapping(".wmlc", "application/vnd.wap.wmlc"); AddMimeMapping(".wmls", "text/vnd.wap.wmlscript"); - AddMimeMapping(".wmlsc", "application/vnd.wap.wmlscriptc"); + AddMimeMapping(".wmlsc", "application/vnd.wap.wmlscriptc"); + AddMimeMapping(".woff2", "application/font-woff2"); AddMimeMapping(".word", "application/msword"); AddMimeMapping(".wp", "application/wordperfect"); AddMimeMapping(".wp5", "application/wordperfect"); diff --git a/common/ASC.Core.Common/Billing/License/License.cs b/common/ASC.Core.Common/Billing/License/License.cs index bb9205f898c..a20073bc137 100644 --- a/common/ASC.Core.Common/Billing/License/License.cs +++ b/common/ASC.Core.Common/Billing/License/License.cs @@ -65,7 +65,16 @@ public class License public string Signature { get; set; } - public bool? DiscEncryption { get; set; } + public bool? DiscEncryption { get; set; } + + [JsonPropertyName("users_count")] + public int DSUsersCount { get; set; } + + [JsonPropertyName("users_expire")] + public int DSUsersExpire { get; set; } + + [JsonPropertyName("connections")] + public int DSConnections { get; set; } public static License Parse(string licenseString) { diff --git a/common/ASC.Core.Common/Caching/CachedTenantService.cs b/common/ASC.Core.Common/Caching/CachedTenantService.cs index 04fc243e34b..1aa26b16daa 100644 --- a/common/ASC.Core.Common/Caching/CachedTenantService.cs +++ b/common/ASC.Core.Common/Caching/CachedTenantService.cs @@ -223,7 +223,11 @@ public IEnumerable GetTenants(string login, string passwordHash) public IEnumerable GetTenants(DateTime from, bool active = true) { return Service.GetTenants(from, active); - } + } + public IEnumerable GetTenants(List ids) + { + return Service.GetTenants(ids); + } public Tenant GetTenant(int id) { diff --git a/common/ASC.Core.Common/Caching/CachedUserService.cs b/common/ASC.Core.Common/Caching/CachedUserService.cs index 6674eeecc23..93037b012b1 100644 --- a/common/ASC.Core.Common/Caching/CachedUserService.cs +++ b/common/ASC.Core.Common/Caching/CachedUserService.cs @@ -61,7 +61,7 @@ public UserServiceCache( ICacheNotify cacheUserInfoItem, ICacheNotify cacheUserPhotoItem, ICacheNotify cacheGroupCacheItem, - ICacheNotify cacheUserGroupRefItem, + ICacheNotify cacheUserGroupRefItem, ICache cache) { TrustInterval = new TrustInterval(); @@ -302,7 +302,11 @@ private UserInfo GetUserForPersonal(int tenant, Guid id) public UserInfo GetUserByPasswordHash(int tenant, string login, string passwordHash) { return Service.GetUserByPasswordHash(tenant, login, passwordHash); - } + } + public IEnumerable GetUsersAllTenants(IEnumerable userIds) + { + return Service.GetUsersAllTenants(userIds); + } public UserInfo SaveUser(int tenant, UserInfo user) { diff --git a/common/ASC.Core.Common/Context/Impl/TenantManager.cs b/common/ASC.Core.Common/Context/Impl/TenantManager.cs index 5f7315fc568..1247aec31d8 100644 --- a/common/ASC.Core.Common/Context/Impl/TenantManager.cs +++ b/common/ASC.Core.Common/Context/Impl/TenantManager.cs @@ -155,7 +155,11 @@ public TenantManager( public List GetTenants(bool active = true) { return TenantService.GetTenants(default, active).ToList(); - } + } + public List GetTenants(List ids) + { + return TenantService.GetTenants(ids).ToList(); + } public Tenant GetTenant(int tenantId) { diff --git a/common/ASC.Core.Common/Core/ITenantService.cs b/common/ASC.Core.Common/Core/ITenantService.cs index 7c913d957f2..d7961a71904 100644 --- a/common/ASC.Core.Common/Core/ITenantService.cs +++ b/common/ASC.Core.Common/Core/ITenantService.cs @@ -39,7 +39,9 @@ public interface ITenantService { void ValidateDomain(string domain); - IEnumerable GetTenants(DateTime from, bool active = true); + IEnumerable GetTenants(DateTime from, bool active = true); + + IEnumerable GetTenants(List ids); IEnumerable GetTenants(string login, string passwordHash); diff --git a/common/ASC.Core.Common/Core/IUserService.cs b/common/ASC.Core.Common/Core/IUserService.cs index 1d5d53eefd2..330574e00d7 100644 --- a/common/ASC.Core.Common/Core/IUserService.cs +++ b/common/ASC.Core.Common/Core/IUserService.cs @@ -91,6 +91,8 @@ IQueryable GetUsers(int tenant, bool isAdmin, UserGroupRef SaveUserGroupRef(int tenant, UserGroupRef r); - void RemoveUserGroupRef(int tenant, Guid userId, Guid groupId, UserGroupRefType refType); + void RemoveUserGroupRef(int tenant, Guid userId, Guid groupId, UserGroupRefType refType); + + IEnumerable GetUsersAllTenants(IEnumerable userIds); } } diff --git a/common/ASC.Core.Common/Data/DbTenantService.cs b/common/ASC.Core.Common/Data/DbTenantService.cs index d16b4297209..245f4dd04fa 100644 --- a/common/ASC.Core.Common/Data/DbTenantService.cs +++ b/common/ASC.Core.Common/Data/DbTenantService.cs @@ -151,7 +151,14 @@ public IEnumerable GetTenants(DateTime from, bool active = true) } return q.Select(FromDbTenantToTenant).ToList(); - } + } + + public IEnumerable GetTenants(List ids) + { + var q = TenantsQuery(); + + return q.Where(r => ids.Contains(r.Id) && r.Status == TenantStatus.Active).Select(FromDbTenantToTenant).ToList(); + } public IEnumerable GetTenants(string login, string passwordHash) { @@ -245,7 +252,7 @@ public Tenant GetTenant(int id) public Tenant GetTenant(string domain) { if (string.IsNullOrEmpty(domain)) throw new ArgumentNullException("domain"); - + domain = domain.ToLowerInvariant(); return TenantsQuery() diff --git a/common/ASC.Core.Common/Data/DbUserService.cs b/common/ASC.Core.Common/Data/DbUserService.cs index a5531a084a4..829de8330e1 100644 --- a/common/ASC.Core.Common/Data/DbUserService.cs +++ b/common/ASC.Core.Common/Data/DbUserService.cs @@ -299,6 +299,14 @@ public UserInfo GetUserByPasswordHash(int tenant, string login, string passwordH } } + public IEnumerable GetUsersAllTenants(IEnumerable userIds) + { + var q = UserDbContext.Users + .Where(r => userIds.Contains(r.Id)) + .Where(r => !r.Removed); + return q.Select(FromUserToUserInfo).ToList(); + } + //todo: remove private void RegeneratePassword(int tenant, Guid userId) { diff --git a/common/ASC.Core.Common/HostedSolution.cs b/common/ASC.Core.Common/HostedSolution.cs index ad6c7e3091a..371269fc21c 100644 --- a/common/ASC.Core.Common/HostedSolution.cs +++ b/common/ASC.Core.Common/HostedSolution.cs @@ -273,9 +273,12 @@ public void SetTariff(int tenant, Tariff tariff) public void SaveButton(int tariffId, string partnerId, string buttonUrl) { TariffService.SaveButton(tariffId, partnerId, buttonUrl); + } + public IEnumerable FindUsers(IEnumerable userIds) + { + return UserService.GetUsersAllTenants(userIds); } - private Tenant AddRegion(Tenant tenant) { if (tenant != null) diff --git a/common/services/ASC.ApiSystem/Controllers/PeopleController.cs b/common/services/ASC.ApiSystem/Controllers/PeopleController.cs new file mode 100644 index 00000000000..23505d66403 --- /dev/null +++ b/common/services/ASC.ApiSystem/Controllers/PeopleController.cs @@ -0,0 +1,140 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + + + + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +using ASC.ApiSystem.Classes; +using ASC.Common; +using ASC.Common.Caching; +using ASC.Common.Logging; +using ASC.Core; +using ASC.Core.Users; +using ASC.Web.Studio.Utility; + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace ASC.ApiSystem.Controllers +{ + [Scope] + [ApiController] + [Route("[controller]")] + public class PeopleController : ControllerBase + { + private ILog Log { get; } + private HostedSolution HostedSolution { get; } + private UserFormatter UserFormatter { get; } + private ICache Cache { get; } + private CoreSettings CoreSettings { get; } + private CommonLinkUtility CommonLinkUtility { get; } + public IHttpContextAccessor HttpContextAccessor { get; } + + public PeopleController( + IOptionsMonitor option, + IOptionsSnapshot hostedSolutionOptions, + UserFormatter userFormatter, + ICache cache, + CoreSettings coreSettings, + CommonLinkUtility commonLinkUtility, + IHttpContextAccessor httpContextAccessor) + { + Log = option.Get("ASC.ApiSystem.People"); + HostedSolution = hostedSolutionOptions.Value; + UserFormatter = userFormatter; + Cache = cache; + CoreSettings = coreSettings; + CommonLinkUtility = commonLinkUtility; + HttpContextAccessor = httpContextAccessor; + } + + #region For TEST api + + [HttpGet("test")] + public IActionResult Check() + { + return Ok(new + { + value = "Portal api works" + }); + } + + #endregion + + #region API methods + + [HttpPost("find")] + [AllowCrossSiteJson] + public IActionResult Find(IEnumerable userIds) + { + var sw = Stopwatch.StartNew(); + userIds = userIds ?? new List(); + + var users = HostedSolution.FindUsers(userIds); + + var result = users.Select(user => new + { + id = user.ID, + name = UserFormatter.GetUserName(user), + email = user.Email, + + link = GetUserProfileLink(user) + }); + + Log.DebugFormat("People find {0} / {1}; Elapsed {2} ms", result.Count(), userIds.Count(), sw.ElapsedMilliseconds); + sw.Stop(); + + return Ok(new + { + result + }); + } + + #endregion + + #region private methods + + private string GetTenantDomain(int tenantId) + { + var domain = Cache.Get(tenantId.ToString()); + if (string.IsNullOrEmpty(domain)) + { + var tenant = HostedSolution.GetTenant(tenantId); + domain = tenant.GetTenantDomain(CoreSettings); + Cache.Insert(tenantId.ToString(), domain, TimeSpan.FromMinutes(10)); + } + return domain; + } + + private string GetUserProfileLink(UserInfo user) + { + var tenantDomain = GetTenantDomain(user.Tenant); + return string.Format("{0}{1}{2}/{3}", + HttpContextAccessor.HttpContext.Request.Scheme, + Uri.SchemeDelimiter, + tenantDomain, + "Products/People/Profile.aspx?" + CommonLinkUtility.GetUserParamsPair(user)); + } + + #endregion + } +} \ No newline at end of file diff --git a/config/appsettings.json b/config/appsettings.json index 52bf8197336..16b40522055 100644 --- a/config/appsettings.json +++ b/config/appsettings.json @@ -56,15 +56,15 @@ "enable": [ "box", "dropboxv2", "docusign", "google", "onedrive", "sharepoint", "nextcloud", "owncloud", "webdav", "kdrive", "yandex" ] }, "docservice": { - "coauthor-docs": [ ".pptx", ".ppsx", ".xlsx", ".csv", ".docx", ".txt" ], - "commented-docs": [ ".docx", ".xlsx", ".pptx" ], + "coauthor-docs": [ ".pptx", ".ppsx", ".xlsx", ".csv", ".docx", ".docxf", ".oform", ".txt" ], + "commented-docs": [ ".docx", ".docxf", ".xlsx", ".pptx" ], "convert-docs": [ ".pptm", ".ppt", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".rtf" ], - "edited-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".csv", ".docx", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".txt", ".rtf", ".mht", ".html", ".htm" ], - "encrypted-docs": [ ".docx", ".xlsx", ".pptx" ], - "formfilling-docs": [ ".docx" ], + "edited-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".csv", ".docx", ".docxf", ".oform", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".txt", ".rtf", ".mht", ".html", ".htm" ], + "encrypted-docs": [ ".docx", ".docxf", ".xlsx", ".pptx" ], + "formfilling-docs": [ ".oform", ], "customfilter-docs": [ ".xlsx" ], - "reviewed-docs": [ ".docx" ], - "viewed-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".gslides", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".gsheet", ".csv", ".docx", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".gdoc", ".txt", ".rtf", ".mht", ".html", ".htm", ".epub", ".pdf", ".djvu", ".xps" ], + "reviewed-docs": [ ".docx", ".docxf" ], + "viewed-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".gslides", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".gsheet", ".csv", ".docx", ".docxf", ".oform", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".gdoc", ".txt", ".rtf", ".mht", ".html", ".htm", ".epub", ".pdf", ".djvu", ".xps" ], "secret": { "value": "", "header": "" diff --git a/products/ASC.Files/Core/Core/Dao/Interfaces/IDaoFactory.cs b/products/ASC.Files/Core/Core/Dao/Interfaces/IDaoFactory.cs index de630293e22..caf1fbbb8fb 100644 --- a/products/ASC.Files/Core/Core/Dao/Interfaces/IDaoFactory.cs +++ b/products/ASC.Files/Core/Core/Dao/Interfaces/IDaoFactory.cs @@ -39,7 +39,9 @@ public interface IDaoFactory ITagDao GetTagDao(); - ISecurityDao GetSecurityDao(); + ISecurityDao GetSecurityDao(); + + ILinkDao GetLinkDao(); IProviderDao ProviderDao { get; } } diff --git a/products/ASC.Files/Core/Core/Dao/Interfaces/ILinkDao.cs b/products/ASC.Files/Core/Core/Dao/Interfaces/ILinkDao.cs new file mode 100644 index 00000000000..cf675f78cd8 --- /dev/null +++ b/products/ASC.Files/Core/Core/Dao/Interfaces/ILinkDao.cs @@ -0,0 +1,31 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2020 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +namespace ASC.Files.Core +{ + public interface ILinkDao + { + void AddLink(string sourceId, string linkedId); + + string GetSource(string linkedId); + + string GetLinked(string sourceId); + + void DeleteLink(string sourceId); + + void DeleteAllLink(string sourceId); + } +} \ No newline at end of file diff --git a/products/ASC.Files/Core/Core/Dao/TeamlabDao/DaoFactory.cs b/products/ASC.Files/Core/Core/Dao/TeamlabDao/DaoFactory.cs index d239835e94d..370d3d2d219 100644 --- a/products/ASC.Files/Core/Core/Dao/TeamlabDao/DaoFactory.cs +++ b/products/ASC.Files/Core/Core/Dao/TeamlabDao/DaoFactory.cs @@ -65,6 +65,11 @@ public ISecurityDao GetSecurityDao() { return ServiceProvider.GetService>(); } + + public ILinkDao GetLinkDao() + { + return ServiceProvider.GetService(); + } } public class DaoFactoryExtension @@ -90,6 +95,8 @@ public static void Register(DIHelper services) services.TryAdd, TagDao>(); services.TryAdd, ProviderTagDao>(); + services.TryAdd(); + // AddSharpBoxDaoSelectorService } } diff --git a/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs index c91ddb6bc91..f810b2849f5 100644 --- a/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs @@ -1379,6 +1379,7 @@ private Func, Selector> GetFuncForSearch(object parentI protected IQueryable FromQueryWithShared(IQueryable dbFiles) { + var cId = AuthContext.CurrentAccount.ID; return from r in dbFiles select new DbFileQuery { @@ -1396,16 +1397,21 @@ select f Shared = (from f in FilesDbContext.Security where f.EntryType == FileEntryType.File && f.EntryId == r.Id.ToString() && f.TenantId == r.TenantId select f - ).Any() + ).Any(), + Linked = (from f in FilesDbContext.FilesLink + where f.TenantId == r.TenantId && f.LinkedId == r.Id.ToString() && f.LinkedFor == cId + select f) + .Any() }; } protected IQueryable FromQuery(IQueryable dbFiles) { + var cId = AuthContext.CurrentAccount.ID; return dbFiles .Select(r => new DbFileQuery { - File = r, + File = r, Root = (from f in FilesDbContext.Folders where f.Id == (from t in FilesDbContext.Tree @@ -1416,7 +1422,11 @@ select t.ParentId where f.TenantId == r.TenantId select f ).FirstOrDefault(), - Shared = true + Shared = true, + Linked = (from f in FilesDbContext.FilesLink + where f.TenantId == r.TenantId && f.LinkedId == r.Id.ToString() && f.LinkedFor == cId + select f) + .Any() }); } @@ -1424,25 +1434,26 @@ public File ToFile(DbFileQuery r) { var file = ServiceProvider.GetService>(); if (r == null) return null; - file.ID = r.File.Id; - file.Title = r.File.Title; - file.FolderID = r.File.FolderId; - file.CreateOn = TenantUtil.DateTimeFromUtc(r.File.CreateOn); - file.CreateBy = r.File.CreateBy; - file.Version = r.File.Version; - file.VersionGroup = r.File.VersionGroup; - file.ContentLength = r.File.ContentLength; - file.ModifiedOn = TenantUtil.DateTimeFromUtc(r.File.ModifiedOn); - file.ModifiedBy = r.File.ModifiedBy; - file.RootFolderType = r.Root?.FolderType ?? default; - file.RootFolderCreator = r.Root?.CreateBy ?? default; - file.RootFolderId = r.Root?.Id ?? default; - file.Shared = r.Shared; - file.ConvertedType = r.File.ConvertedType; - file.Comment = r.File.Comment; - file.Encrypted = r.File.Encrypted; + file.ID = r.File.Id; + file.Title = r.File.Title; + file.FolderID = r.File.FolderId; + file.CreateOn = TenantUtil.DateTimeFromUtc(r.File.CreateOn); + file.CreateBy = r.File.CreateBy; + file.Version = r.File.Version; + file.VersionGroup = r.File.VersionGroup; + file.ContentLength = r.File.ContentLength; + file.ModifiedOn = TenantUtil.DateTimeFromUtc(r.File.ModifiedOn); + file.ModifiedBy = r.File.ModifiedBy; + file.RootFolderType = r.Root?.FolderType ?? default; + file.RootFolderCreator = r.Root?.CreateBy ?? default; + file.RootFolderId = r.Root?.Id ?? default; + file.Shared = r.Shared; + file.ConvertedType = r.File.ConvertedType; + file.Comment = r.File.Comment; + file.Encrypted = r.File.Encrypted; file.Forcesave = r.File.Forcesave; - file.ThumbnailStatus = r.File.Thumb; + file.ThumbnailStatus = r.File.Thumb; + file.IsFillFormDraft = r.Linked; return file; } @@ -1532,9 +1543,10 @@ internal protected async Task InitDocumentAsync(DbFile dbFile) public class DbFileQuery { - public DbFile File { get; set; } - public DbFolder Root { get; set; } - public bool Shared { get; set; } + public DbFile File { get; set; } + public DbFolder Root { get; set; } + public bool Shared { get; set; } + public bool Linked { get; set; } } public class DbFileQueryWithSecurity diff --git a/products/ASC.Files/Core/Core/Dao/TeamlabDao/LinkDao.cs b/products/ASC.Files/Core/Core/Dao/TeamlabDao/LinkDao.cs new file mode 100644 index 00000000000..3097396c8ed --- /dev/null +++ b/products/ASC.Files/Core/Core/Dao/TeamlabDao/LinkDao.cs @@ -0,0 +1,116 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2020 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + + +using System; +using System.Linq; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Core; +using ASC.Core.Common.EF; +using ASC.Core.Common.Settings; +using ASC.Core.Tenants; +using ASC.Files.Core.EF; +using ASC.Web.Studio.Core; +using ASC.Web.Studio.UserControls.Statistics; +using ASC.Web.Studio.Utility; + +namespace ASC.Files.Core.Data +{ + [Scope] + internal class LinkDao : AbstractDao, ILinkDao + { + public DbContextManager DbContextManager { get; } + + public LinkDao( + UserManager userManager, + DbContextManager dbContextManager, + TenantManager tenantManager, + TenantUtil tenantUtil, + SetupInfo setupInfo, + TenantExtra tenantExtra, + TenantStatisticsProvider tenantStatisticProvider, + CoreBaseSettings coreBaseSettings, + CoreConfiguration coreConfiguration, + SettingsManager settingsManager, + AuthContext authContext, + IServiceProvider serviceProvider, + ICache cache) + : base( + dbContextManager, + userManager, + tenantManager, + tenantUtil, + setupInfo, + tenantExtra, + tenantStatisticProvider, + coreBaseSettings, + coreConfiguration, + settingsManager, + authContext, + serviceProvider, + cache) + { } + + public void AddLink(string sourceId, string linkedId) + { + FilesDbContext.AddOrUpdate(r => r.FilesLink, new DbFilesLink() + { + TenantId = TenantID, + SourceId = sourceId, + LinkedId = linkedId, + LinkedFor = AuthContext.CurrentAccount.ID + }); + + FilesDbContext.SaveChanges(); + } + + public string GetSource(string linkedId) + { + return FilesDbContext.FilesLink + .Where(r => r.TenantId == TenantID && r.LinkedId == linkedId && r.LinkedFor == AuthContext.CurrentAccount.ID) + .Select(r => r.SourceId) + .SingleOrDefault(); + } + + public string GetLinked(string sourceId) + { + return FilesDbContext.FilesLink + .Where(r => r.TenantId == TenantID && r.SourceId == sourceId && r.LinkedFor == AuthContext.CurrentAccount.ID) + .Select(r => r.LinkedId) + .SingleOrDefault(); + } + + public void DeleteLink(string sourceId) + { + var link = FilesDbContext.FilesLink + .Where(r => r.TenantId == TenantID && r.SourceId == sourceId && r.LinkedFor == AuthContext.CurrentAccount.ID) + .SingleOrDefault(); + + FilesDbContext.FilesLink.Remove(link); + FilesDbContext.SaveChanges(); + } + + public void DeleteAllLink(string fileId) + { + var link = FilesDbContext.FilesLink.Where(r => r.TenantId == TenantID && (r.SourceId == fileId || r.LinkedId == fileId)); + + FilesDbContext.FilesLink.RemoveRange(link); + FilesDbContext.SaveChanges(); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Core/Core/Dao/TeamlabDao/TagDao.cs b/products/ASC.Files/Core/Core/Dao/TeamlabDao/TagDao.cs index 851cb0fdac0..badfeec8aec 100644 --- a/products/ASC.Files/Core/Core/Dao/TeamlabDao/TagDao.cs +++ b/products/ASC.Files/Core/Core/Dao/TeamlabDao/TagDao.cs @@ -276,12 +276,14 @@ private void DeleteTagsBeforeSave() FilesDbContext.TagLink.RemoveRange(linksToRemove); } - FilesDbContext.SaveChanges(); - - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Any(a => a.TagId == r.Id)); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + FilesDbContext.SaveChanges(); + + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); FilesDbContext.SaveChanges(); } diff --git a/products/ASC.Files/Core/Core/EF/DbFilesLink.cs b/products/ASC.Files/Core/Core/EF/DbFilesLink.cs new file mode 100644 index 00000000000..688ec72a34f --- /dev/null +++ b/products/ASC.Files/Core/Core/EF/DbFilesLink.cs @@ -0,0 +1,98 @@ + +using System; + +using ASC.Core.Common.EF; +using ASC.Core.Common.EF.Model; + +using Microsoft.EntityFrameworkCore; + +namespace ASC.Files.Core.EF +{ + public class DbFilesLink : BaseEntity, IDbFile + { + public int TenantId { get; set; } + public string SourceId { get; set; } + public string LinkedId { get; set; } + public Guid LinkedFor { get; set; } + + public override object[] GetKeys() + { + return new object[] { TenantId, SourceId, LinkedId }; + } + } + + public static class DbFilesLinkExtension + { + public static ModelBuilderWrapper AddDbFilesLink(this ModelBuilderWrapper modelBuilder) + { + modelBuilder + .Add(MySqlAddDbFilesLink, Provider.MySql) + .Add(PgSqlAddDbFilesLink, Provider.Postgre); + return modelBuilder; + } + public static void MySqlAddDbFilesLink(this ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasKey(e => new { e.TenantId, e.SourceId, e.LinkedId }) + .HasName("PRIMARY"); + + entity.ToTable("files_link"); + + entity.HasIndex(e => new { e.TenantId, e.SourceId, e.LinkedId, e.LinkedFor }) + .HasDatabaseName("linked_for"); + + entity.Property(e => e.TenantId).HasColumnName("tenant_id"); + + entity.Property(e => e.SourceId) + .HasColumnName("source_id") + .HasColumnType("varchar(32)") + .HasCharSet("utf8") + .UseCollation("utf8_general_ci"); + + entity.Property(e => e.LinkedId) + .HasColumnName("linked_id") + .HasColumnType("varchar(32)") + .HasCharSet("utf8") + .UseCollation("utf8_general_ci"); + + entity.Property(e => e.LinkedFor) + .HasColumnName("linked_for") + .HasColumnType("char(38)") + .HasCharSet("utf8") + .UseCollation("utf8_general_ci"); + }); + } + + public static void PgSqlAddDbFilesLink(this ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasKey(e => new { e.TenantId, e.SourceId, e.LinkedId }) + .HasName("files_link_pkey"); + + entity.ToTable("files_link", "onlyoffice"); + + entity.HasIndex(e => new { e.TenantId, e.SourceId, e.LinkedId, e.LinkedFor }) + .HasDatabaseName("linked_for_files_link"); + + entity.Property(e => e.TenantId).HasColumnName("tenant_id"); + + entity.Property(e => e.LinkedId) + .HasColumnName("linked_id") + .HasMaxLength(32); + + entity.Property(e => e.SourceId) + .HasColumnName("source_id") + .HasMaxLength(32); + + entity.Property(e => e.LinkedFor) + .HasColumnName("linked_for") + .HasMaxLength(38) + .IsFixedLength() + .HasDefaultValueSql("NULL::bpchar"); + }); + } + } + +} diff --git a/products/ASC.Files/Core/Core/EF/FilesDbContext.cs b/products/ASC.Files/Core/Core/EF/FilesDbContext.cs index 92f876826ab..16683f6d4fd 100644 --- a/products/ASC.Files/Core/Core/EF/FilesDbContext.cs +++ b/products/ASC.Files/Core/Core/EF/FilesDbContext.cs @@ -4,6 +4,7 @@ using ASC.Common; using ASC.Core.Common.EF; using ASC.Core.Common.EF.Model; + using Microsoft.EntityFrameworkCore; namespace ASC.Files.Core.EF { @@ -21,7 +22,8 @@ public class FilesDbContext : BaseDbContext public DbSet TagLink { get; set; } public DbSet Tag { get; set; } public DbSet ThirdpartyApp { get; set; } - public DbSet Tenants { get; set; } + public DbSet Tenants { get; set; } + public DbSet FilesLink { get; set; } protected override Dictionary> ProviderContext { get @@ -47,7 +49,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .AddDbFilesTagLink() .AddDbFilesTag() .AddDbDbFilesThirdpartyApp() - .AddDbTenant(); + .AddDbTenant() + .AddDbFilesLink(); } } diff --git a/products/ASC.Files/Core/Core/Entries/File.cs b/products/ASC.Files/Core/Core/Entries/File.cs index 687f2dcbe57..8a8584ff7aa 100644 --- a/products/ASC.Files/Core/Core/Entries/File.cs +++ b/products/ASC.Files/Core/Core/Entries/File.cs @@ -51,13 +51,15 @@ public enum FileStatus IsFavorite = 0x20, - IsTemplate = 0x40 + IsTemplate = 0x40, + + IsFillFormDraft = 0x80 } [Transient] [Serializable] [DebuggerDisplay("{Title} ({ID} v{Version})")] - public class File : FileEntry + public class File : FileEntry, IFileEntry { private FileStatus _status; @@ -68,7 +70,7 @@ public File() FileEntryType = FileEntryType.File; } - public File(FileHelper fileHelper): this() + public File(FileHelper fileHelper) : this() { FileHelper = fileHelper; } @@ -179,7 +181,19 @@ public bool IsTemplate _status &= ~FileStatus.IsTemplate; } } - + + [JsonIgnore] + public bool IsFillFormDraft + { + get { return (_status & FileStatus.IsFillFormDraft) == FileStatus.IsFillFormDraft; } + set + { + if (value) + _status |= FileStatus.IsFillFormDraft; + else + _status &= ~FileStatus.IsFillFormDraft; + } + } public bool Encrypted { get; set; } public Thumbnail ThumbnailStatus { get; set; } diff --git a/products/ASC.Files/Core/Core/Entries/FileEntry.cs b/products/ASC.Files/Core/Core/Entries/FileEntry.cs index d56d2cf4447..908d5d5fc4b 100644 --- a/products/ASC.Files/Core/Core/Entries/FileEntry.cs +++ b/products/ASC.Files/Core/Core/Entries/FileEntry.cs @@ -113,8 +113,15 @@ public object Clone() } } - [Serializable] - public abstract class FileEntry : FileEntry, ICloneable + + public interface IFileEntry + { + string UniqID { get; } + } + + + [Serializable] + public abstract class FileEntry : FileEntry, ICloneable, IFileEntry { public T ID { get; set; } diff --git a/products/ASC.Files/Core/Core/FileStorageService.cs b/products/ASC.Files/Core/Core/FileStorageService.cs index b540cfaaf3b..4df9b054fd1 100644 --- a/products/ASC.Files/Core/Core/FileStorageService.cs +++ b/products/ASC.Files/Core/Core/FileStorageService.cs @@ -56,6 +56,7 @@ using ASC.Web.Core.PublicResources; using ASC.Web.Core.Users; using ASC.Web.Files.Classes; +using ASC.Web.Files.Core.Compress; using ASC.Web.Files.Core.Entries; using ASC.Web.Files.Helpers; using ASC.Web.Files.Services.DocumentService; @@ -119,6 +120,7 @@ public class FileStorageService //: IFileStorageService private FileTrackerHelper FileTracker { get; } private ICacheNotify ThumbnailNotify { get; } private EntryStatusManager EntryStatusManager { get; } + public CompressToArchive CompressToArchive { get; } private ILog Logger { get; set; } public FileStorageService( @@ -163,7 +165,8 @@ public FileStorageService( TenantManager tenantManager, FileTrackerHelper fileTracker, ICacheNotify thumbnailNotify, - EntryStatusManager entryStatusManager) + EntryStatusManager entryStatusManager, + CompressToArchive compressToArchive) { Global = global; GlobalStore = globalStore; @@ -207,6 +210,7 @@ public FileStorageService( FileTracker = fileTracker; ThumbnailNotify = thumbnailNotify; EntryStatusManager = entryStatusManager; + CompressToArchive = compressToArchive; } public Folder GetFolder(T folderId) @@ -588,24 +592,24 @@ public File CreateNewFile(FileModel fileWrapper, bool enableExternalExt = } var externalExt = false; - - var fileExt = !enableExternalExt ? FileUtility.GetInternalExtension(fileWrapper.Title) : FileUtility.GetFileExtension(fileWrapper.Title); - if (!FileUtility.InternalExtension.Values.Contains(fileExt)) + var title = fileWrapper.Title; + var fileExt = FileUtility.GetFileExtension(title); + if (fileExt != FileUtility.MasterFormExtension) { - if (!enableExternalExt) + fileExt = FileUtility.GetInternalExtension(title); + if (!FileUtility.InternalExtension.Values.Contains(fileExt)) { fileExt = FileUtility.InternalExtension[FileType.Document]; - file.Title = fileWrapper.Title + fileExt; + file.Title = title + fileExt; } else { - externalExt = true; - file.Title = fileWrapper.Title; + file.Title = FileUtility.ReplaceFileExtension(title, fileExt); } } else { - file.Title = FileUtility.ReplaceFileExtension(fileWrapper.Title, fileExt); + file.Title = FileUtility.ReplaceFileExtension(title, fileExt); } if (EqualityComparer.Default.Equals(fileWrapper.TemplateId, default(T))) @@ -752,7 +756,7 @@ public File SaveEditing(T fileId, string fileExtension, string fileuri, Strea FileTracker.Remove(fileId); } - var file = EntryManager.SaveEditing(fileId, fileExtension, fileuri, stream, doc, forcesave: forcesave ? ForcesaveType.User : ForcesaveType.None); + var file = EntryManager.SaveEditing(fileId, fileExtension, fileuri, stream, doc, forcesave: forcesave ? ForcesaveType.User : ForcesaveType.None, keepLink: true); if (file != null) FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdated, file.Title); @@ -1584,6 +1588,54 @@ public List CheckConversion(List> filesInfoJSO } } + public string CheckFillFormDraft(T fileId, int version, string doc, bool editPossible, bool view) + { + var file = DocumentServiceHelper.GetParams(fileId, version, doc, editPossible, !view, true, out var _configuration); + var _valideShareLink = !string.IsNullOrEmpty(FileShareLink.Parse(doc)); + + if (_valideShareLink) + { + _configuration.Document.SharedLinkKey += doc; + } + + if (_configuration.EditorConfig.ModeWrite + && FileUtility.CanWebRestrictedEditing(file.Title) + && FileSecurity.CanFillForms(file) + && !FileSecurity.CanEdit(file)) + { + if (!file.IsFillFormDraft) + { + FileMarker.RemoveMarkAsNew(file); + + Folder folderIfNew; + File form; + try + { + form = EntryManager.GetFillFormDraft(file, out folderIfNew); + } + catch (Exception ex) + { + Logger.Error("DocEditor", ex); + throw; + } + + var comment = folderIfNew == null + ? string.Empty + : "#message/" + HttpUtility.UrlEncode(string.Format(FilesCommonResource.MessageFillFormDraftCreated, folderIfNew.Title)); + + return FilesLinkUtility.GetFileWebEditorUrl(form.ID) + comment; + } + else if (!EntryManager.CheckFillFormDraft(file)) + { + var comment = "#message/" + HttpUtility.UrlEncode(FilesCommonResource.MessageFillFormDraftDiscard); + + return FilesLinkUtility.GetFileWebEditorUrl(file.ID) + comment; + } + } + + return FilesLinkUtility.GetFileWebEditorUrl(file.ID); + } + public void ReassignStorage(Guid userFromId, Guid userToId) { //check current user have access @@ -1662,6 +1714,7 @@ public void DeleteStorage(Guid userId) var folderDao = GetFolderDao(); var fileDao = GetFileDao(); + var linkDao = GetLinkDao(); //delete all markAsNew var rootFoldersId = new List @@ -1686,7 +1739,7 @@ public void DeleteStorage(Guid userId) //delete all from My if (!Equals(folderIdFromMy, 0)) { - EntryManager.DeleteSubitems(folderIdFromMy, folderDao, fileDao); + EntryManager.DeleteSubitems(folderIdFromMy, folderDao, fileDao, linkDao); //delete My userFrom folder folderDao.DeleteFolder(folderIdFromMy); @@ -1697,7 +1750,7 @@ public void DeleteStorage(Guid userId) var folderIdFromTrash = folderDao.GetFolderIDTrash(false, userId); if (!Equals(folderIdFromTrash, 0)) { - EntryManager.DeleteSubitems(folderIdFromTrash, folderDao, fileDao); + EntryManager.DeleteSubitems(folderIdFromTrash, folderDao, fileDao, linkDao); folderDao.DeleteFolder(folderIdFromTrash); GlobalFolderHelper.FolderTrash = userId; } @@ -2274,11 +2327,11 @@ public bool DisplayTemplates(bool set) return FilesSettingsHelper.TemplatesSection; } - public bool ChangeDownloadTarGz(bool set) + public ICompress ChangeDownloadTarGz(bool set) { FilesSettingsHelper.DownloadTarGz = set; - return FilesSettingsHelper.DownloadTarGz; + return CompressToArchive; } public bool ChangeDeleteConfrim(bool set) @@ -2350,6 +2403,11 @@ private ISecurityDao GetSecurityDao() return DaoFactory.GetSecurityDao(); } + private ILinkDao GetLinkDao() + { + return DaoFactory.GetLinkDao(); + } + private static void ErrorIf(bool condition, string errorMessage) { if (condition) throw new InvalidOperationException(errorMessage); diff --git a/products/ASC.Files/Core/Core/Security/FileSecurity.cs b/products/ASC.Files/Core/Core/Security/FileSecurity.cs index 20c5b58876d..f9fc79937bf 100644 --- a/products/ASC.Files/Core/Core/Security/FileSecurity.cs +++ b/products/ASC.Files/Core/Core/Security/FileSecurity.cs @@ -418,96 +418,116 @@ private IEnumerable> Filter(IEnumerable> entries, F { continue; } - - if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((IFolder)e).FolderType == FolderType.Projects) - { - // Root Projects folder read-only - continue; - } - - if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((IFolder)e).FolderType == FolderType.SHARE) - { - // Root Share folder read-only - continue; - } - if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((IFolder)e).FolderType == FolderType.Recent) - { - // Recent folder read-only - continue; - } + var folder = e as Folder; + var file = e as File; - if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((IFolder)e).FolderType == FolderType.Favorites) + if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder) { - // Favorites folder read-only - continue; + if (folder == null) continue; + + if (folder.FolderType == FolderType.Projects) + { + // Root Projects folder read-only + continue; + } + + if (folder.FolderType == FolderType.SHARE) + { + // Root Share folder read-only + continue; + } + + if (folder.FolderType == FolderType.Recent) + { + // Recent folder read-only + continue; + } + + if (folder.FolderType == FolderType.Favorites) + { + // Favorites folder read-only + continue; + } + + if (folder.FolderType == FolderType.Templates) + { + // Templates folder read-only + continue; + } } - if (action != FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && ((IFolder)e).FolderType == FolderType.Templates) + if (isVisitor && e.ProviderEntry) { - // Templates folder read-only continue; } - - if (isVisitor && e.ProviderEntry) - { - continue; - } - - if (e.RootFolderType == FolderType.USER && e.RootFolderCreator == userId && !isVisitor) - { - // user has all right in his folder - result.Add(e); - continue; - } - if (e.RootFolderType == FolderType.Privacy && e.RootFolderCreator == userId && !isVisitor) + if (e.FileEntryType == FileEntryType.File + && file.IsFillFormDraft) { - // user has all right in his privacy folder - result.Add(e); - continue; - } - - if (DefaultCommonShare == FileShare.Read && action == FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && - ((IFolder)e).FolderType == FolderType.COMMON) - { - // all can read Common folder - result.Add(e); - continue; - } - - if (action == FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && - ((IFolder)e).FolderType == FolderType.SHARE) - { - // all can read Share folder - result.Add(e); - continue; + e.Access = FileShare.FillForms; + + if (action != FilesSecurityActions.Read + && action != FilesSecurityActions.FillForms + && action != FilesSecurityActions.Delete) + { + continue; + } } - if (action == FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && - ((IFolder)e).FolderType == FolderType.Recent) + if (e.RootFolderType == FolderType.USER && e.RootFolderCreator == userId && !isVisitor) { - // all can read recent folder + // user has all right in his folder result.Add(e); continue; } - if (action == FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && - ((IFolder)e).FolderType == FolderType.Favorites) + if (e.RootFolderType == FolderType.Privacy && e.RootFolderCreator == userId && !isVisitor) { - // all can read favorites folder + // user has all right in his privacy folder result.Add(e); continue; } - if (action == FilesSecurityActions.Read && e.FileEntryType == FileEntryType.Folder && - ((IFolder)e).FolderType == FolderType.Templates) + if (e.FileEntryType == FileEntryType.Folder) { - // all can read templates folder - result.Add(e); - continue; + if (folder == null) continue; + + if (DefaultCommonShare == FileShare.Read && action == FilesSecurityActions.Read && folder.FolderType == FolderType.COMMON) + { + // all can read Common folder + result.Add(e); + continue; + } + + if (action == FilesSecurityActions.Read && folder.FolderType == FolderType.SHARE) + { + // all can read Share folder + result.Add(e); + continue; + } + + if (action == FilesSecurityActions.Read && folder.FolderType == FolderType.Recent) + { + // all can read recent folder + result.Add(e); + continue; + } + + if (action == FilesSecurityActions.Read && folder.FolderType == FolderType.Favorites) + { + // all can read favorites folder + result.Add(e); + continue; + } + + if (action == FilesSecurityActions.Read && folder.FolderType == FolderType.Templates) + { + // all can read templates folder + result.Add(e); + continue; + } } - if (e.RootFolderType == FolderType.COMMON && FileSecurityCommon.IsAdministrator(userId)) { @@ -532,7 +552,7 @@ private IEnumerable> Filter(IEnumerable> entries, F if (ace == null) { // share on parent folders - ace = shares.Where(r => Equals(r.EntryId, ((File)e).FolderID) && r.EntryType == FileEntryType.Folder) + ace = shares.Where(r => Equals(r.EntryId, file.FolderID) && r.EntryType == FileEntryType.Folder) .OrderBy(r => r, new SubjectComparer(subjects)) .ThenBy(r => r.Level) .ThenByDescending(r => r.Share, new FileShareRecord.ShareComparer()) @@ -565,7 +585,7 @@ private IEnumerable> Filter(IEnumerable> entries, F else if (action == FilesSecurityActions.CustomFilter && (e.Access == FileShare.CustomFilter || e.Access == FileShare.ReadWrite)) result.Add(e); else if (action == FilesSecurityActions.Edit && e.Access == FileShare.ReadWrite) result.Add(e); else if (action == FilesSecurityActions.Create && e.Access == FileShare.ReadWrite) result.Add(e); - else if (e.Access != FileShare.Restrict && e.CreateBy == userId && (e.FileEntryType == FileEntryType.File || ((IFolder)e).FolderType != FolderType.COMMON)) result.Add(e); + else if (e.Access != FileShare.Restrict && e.CreateBy == userId && (e.FileEntryType == FileEntryType.File || folder.FolderType != FolderType.COMMON)) result.Add(e); if (e.CreateBy == userId) e.Access = FileShare.None; //HACK: for client } @@ -705,7 +725,7 @@ public List GetSharesForMe(FilterType filterType, bool subjectGroup, var records = securityDao.GetShares(subjects); var result = new List(); - result.AddRange(GetSharesForMe(records.Where(r=> r.EntryId.GetType() == typeof(int)), subjects, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders)); + result.AddRange(GetSharesForMe(records.Where(r => r.EntryId.GetType() == typeof(int)), subjects, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders)); result.AddRange(GetSharesForMe(records.Where(r => r.EntryId.GetType() == typeof(string)), subjects, filterType, subjectGroup, subjectID, searchText, searchInContent, withSubfolders)); return result; } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs index dfd6f18af05..cf19e2e7b9f 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs @@ -322,10 +322,12 @@ public void DeleteFile(string fileId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFolderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFolderDao.cs index 121493da3a1..b7c9b9635cf 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFolderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFolderDao.cs @@ -228,10 +228,12 @@ public void DeleteFolder(string folderId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs index d129bb39410..0a45a737b7f 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -324,11 +324,13 @@ public void DeleteFile(string fileId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFolderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFolderDao.cs index 41953eb9230..90d6f113fd0 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFolderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFolderDao.cs @@ -227,12 +227,14 @@ public void DeleteFolder(string folderId) .ToList(); FilesDbContext.TagLink.RemoveRange(link); - FilesDbContext.SaveChanges(); - - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + FilesDbContext.SaveChanges(); + + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index 715c0c8856d..f24d2ccc0b4 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -317,10 +317,12 @@ public void DeleteFile(string fileId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs index eed396f844e..d45c02abd9e 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFolderDao.cs @@ -217,10 +217,12 @@ public void DeleteFolder(string folderId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); @@ -404,7 +406,7 @@ public bool UseTrashForRemove(Folder folder) public bool UseRecursiveOperation(string folderId, string toRootFolderId) { - return false; + return true; } public bool UseRecursiveOperation(string folderId, TTo toRootFolderId) diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs index 10d6e74c68a..54ea11b932d 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs @@ -413,8 +413,8 @@ public void Transfer(ResumableUploadSession googleDriveSession, Stream stream, l response = (HttpWebResponse)request.GetResponse(); } catch (WebException exception) - { - if (exception.Status == WebExceptionStatus.ProtocolError) + { + if (exception.Status == WebExceptionStatus.ProtocolError || exception.Status == WebExceptionStatus.UnknownError) //Status is UnknownError (unix) { if (exception.Response != null && exception.Response.Headers.AllKeys.Contains("Range")) { diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index 0c5f3b9ed34..38f9ef47040 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -320,10 +320,12 @@ public void DeleteFile(string fileId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs index bfd01a065d1..faa3e485e0c 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFolderDao.cs @@ -65,7 +65,7 @@ public OneDriveFolderDao( CrossDao crossDao, OneDriveDaoSelector oneDriveDaoSelector, IFileDao fileDao, - IFolderDao folderDao, + IFolderDao folderDao, TempPath tempPath) : base(serviceProvider, userManager, tenantManager, tenantUtil, dbContextManager, setupInfo, monitor, fileUtility, tempPath) { @@ -225,10 +225,12 @@ public void DeleteFolder(string folderId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs index 755ebbb443f..4836c01d9b9 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderDaoBase.cs @@ -96,7 +96,7 @@ public IDaoSelector GetSelector(string id) protected void SetSharedProperty(IEnumerable> entries) { - SecurityDao.GetPureShareRecords(entries.ToArray()) + SecurityDao.GetPureShareRecords(entries) //.Where(x => x.Owner == SecurityContext.CurrentAccount.ID) .Select(x => x.EntryId).Distinct().ToList() .ForEach(id => diff --git a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFolderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFolderDao.cs index 0fdb5dc800f..59b70cfa9cf 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFolderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFolderDao.cs @@ -222,10 +222,12 @@ public void DeleteFolder(string folderId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index 887438298a3..858fbce9ae0 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -360,10 +360,12 @@ public void DeleteFile(string fileId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs index 5f99a29e494..b398dbcdb93 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFolderDao.cs @@ -238,10 +238,12 @@ public void DeleteFolder(string folderId) FilesDbContext.TagLink.RemoveRange(link); FilesDbContext.SaveChanges(); - var tagsToRemove = Query(FilesDbContext.Tag) - .Where(r => !Query(FilesDbContext.TagLink).Where(a => a.TagId == r.Id).Any()); - - FilesDbContext.Tag.RemoveRange(tagsToRemove); + var tagsToRemove = from ft in FilesDbContext.Tag + join ftl in FilesDbContext.TagLink.DefaultIfEmpty() on new { TenantId = ft.TenantId, Id = ft.Id } equals new { TenantId = ftl.TenantId, Id = ftl.TagId } + where ftl == null + select ft; + + FilesDbContext.Tag.RemoveRange(tagsToRemove.ToList()); var securityToDelete = Query(FilesDbContext.Security) .Where(r => hashIDs.Any(h => h == r.EntryId)); diff --git a/products/ASC.Files/Core/HttpHandlers/ChunkedUploaderHandler.cs b/products/ASC.Files/Core/HttpHandlers/ChunkedUploaderHandler.cs index 034c2111188..4e4b65d0199 100644 --- a/products/ASC.Files/Core/HttpHandlers/ChunkedUploaderHandler.cs +++ b/products/ASC.Files/Core/HttpHandlers/ChunkedUploaderHandler.cs @@ -211,8 +211,8 @@ private bool TryAuthorize(ChunkedRequestHelper request) if (uploadSession != null) { TenantManager.SetCurrentTenant(uploadSession.TenantId); - SecurityContext.AuthenticateMeWithoutCookie(AuthManager.GetAccountByID(TenantManager.GetCurrentTenant().TenantId, uploadSession.UserId)); - var culture = SetupInfo.EnabledCulturesPersonal.Find(c => string.Equals(c.Name, uploadSession.CultureName, StringComparison.InvariantCultureIgnoreCase)); + SecurityContext.AuthenticateMeWithoutCookie(AuthManager.GetAccountByID(TenantManager.GetCurrentTenant().TenantId, uploadSession.UserId)); + var culture = SetupInfo.GetPersonalCulture(uploadSession.CultureName).Value; if (culture != null) Thread.CurrentThread.CurrentUICulture = culture; return true; @@ -361,7 +361,7 @@ public CultureInfo CultureInfo(SetupInfo setupInfo) var culture = _request.Query["culture"]; if (string.IsNullOrEmpty(culture)) culture = "en-US"; - return _cultureInfo = setupInfo.EnabledCulturesPersonal.Find(c => string.Equals(c.Name, culture, StringComparison.InvariantCultureIgnoreCase)); + return _cultureInfo = setupInfo.GetPersonalCulture(culture).Value; } public bool Encrypted diff --git a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs index 424ea220b11..d67da68f512 100644 --- a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs @@ -1112,8 +1112,12 @@ private async Task CreateFile(HttpContext context, T folderId) FileMarker.MarkAsNew(file); if (responseMessage) - { - await context.Response.WriteAsync("ok: " + string.Format(FilesCommonResource.MessageFileCreated, folder.Title)); + { + var message = string.Format(FilesCommonResource.MessageFileCreated, folder.Title); + if (FileUtility.CanWebRestrictedEditing(file.Title)) + message = string.Format(FilesCommonResource.MessageFileCreatedForm, folder.Title); + + await context.Response.WriteAsync("ok: " + message); return; } diff --git a/products/ASC.Files/Core/Model/CheckFillFormDraftModel.cs b/products/ASC.Files/Core/Model/CheckFillFormDraftModel.cs new file mode 100644 index 00000000000..fa772f6ab57 --- /dev/null +++ b/products/ASC.Files/Core/Model/CheckFillFormDraftModel.cs @@ -0,0 +1,26 @@ +using System; + +namespace ASC.Files.Core.Model +{ + public class CheckFillFormDraftModel + { + public int Version { get; set; } + public string Doc { get; set; } + public string Action { get; set; } + + public bool RequestView + { + get { return (Action ?? "").Equals("view", StringComparison.InvariantCultureIgnoreCase); } + } + + public bool RequestEmbedded + { + get + { + return + (Action ?? "").Equals("embedded", StringComparison.InvariantCultureIgnoreCase) + && !string.IsNullOrEmpty(Doc); + } + } + } +} diff --git a/products/ASC.Files/Core/Model/PrivacyRoomModel.cs b/products/ASC.Files/Core/Model/PrivacyRoomModel.cs index c3f115b5441..e95f8c5f445 100644 --- a/products/ASC.Files/Core/Model/PrivacyRoomModel.cs +++ b/products/ASC.Files/Core/Model/PrivacyRoomModel.cs @@ -5,5 +5,6 @@ public class PrivacyRoomModel public string PublicKey { get; set; } public string PrivateKeyEnc { get; set; } public bool Enable { get; set; } + public bool Update { get; set; } } } diff --git a/products/ASC.Files/Core/Resources/FilesCommonResource.Designer.cs b/products/ASC.Files/Core/Resources/FilesCommonResource.Designer.cs index 49cea8bea83..e9cc4390112 100644 --- a/products/ASC.Files/Core/Resources/FilesCommonResource.Designer.cs +++ b/products/ASC.Files/Core/Resources/FilesCommonResource.Designer.cs @@ -19,7 +19,7 @@ namespace ASC.Files.Core.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class FilesCommonResource { @@ -213,6 +213,15 @@ public static string CommentCreateByDocuSign { } } + /// + /// Looks up a localized string similar to Created to fill in the form. + /// + public static string CommentCreateFillFormDraft { + get { + return ResourceManager.GetString("CommentCreateFillFormDraft", resourceCulture); + } + } + /// /// Looks up a localized string similar to Edited. /// @@ -807,6 +816,33 @@ public static string MessageFileCreated { } } + /// + /// Looks up a localized string similar to The fillable OFORM document is ready. It is saved in the {0}. + /// + public static string MessageFileCreatedForm { + get { + return ResourceManager.GetString("MessageFileCreatedForm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The oform copy is created in the {0} folder. Please fill out the form and download the result as a PDF or DOCX file.. + /// + public static string MessageFillFormDraftCreated { + get { + return ResourceManager.GetString("MessageFillFormDraftCreated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The file is no longer a draft to fill in the form.. + /// + public static string MessageFillFormDraftDiscard { + get { + return ResourceManager.GetString("MessageFillFormDraftDiscard", resourceCulture); + } + } + /// /// Looks up a localized string similar to Do the same as a user|Link Dropbox, Box and other accounts in the 'Common' section|Set up access rights to the documents and folders in the 'Common' section. /// diff --git a/products/ASC.Files/Core/Resources/FilesCommonResource.resx b/products/ASC.Files/Core/Resources/FilesCommonResource.resx index 756644b9bf6..b66f4bcab7d 100644 --- a/products/ASC.Files/Core/Resources/FilesCommonResource.resx +++ b/products/ASC.Files/Core/Resources/FilesCommonResource.resx @@ -1,5 +1,64 @@  + @@ -53,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.6.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Outside portal @@ -109,6 +168,9 @@ Created by DocuSign + + Created to fill in the form + Edited @@ -307,6 +369,15 @@ File created in folder "{0}" + + The fillable OFORM document is ready. It is saved in the {0} + + + The oform copy is created in the {0} folder. Please fill out the form and download the result as a PDF or DOCX file. + + + The file is no longer a draft to fill in the form. + Do the same as a user|Link Dropbox, Box and other accounts in the 'Common' section|Set up access rights to the documents and folders in the 'Common' section diff --git a/products/ASC.Files/Core/Services/DocumentService/Configuration.cs b/products/ASC.Files/Core/Services/DocumentService/Configuration.cs index f123c249b25..7982011b9c3 100644 --- a/products/ASC.Files/Core/Services/DocumentService/Configuration.cs +++ b/products/ASC.Files/Core/Services/DocumentService/Configuration.cs @@ -865,10 +865,12 @@ public class LogoConfig public LogoConfig( SettingsManager settingsManager, BaseCommonLinkUtility baseCommonLinkUtility, - TenantLogoHelper tenantLogoHelper) + TenantLogoHelper tenantLogoHelper, + FileUtility fileUtility) { BaseCommonLinkUtility = baseCommonLinkUtility; TenantLogoHelper = tenantLogoHelper; + FileUtility = fileUtility; SettingsManager = settingsManager; } @@ -883,9 +885,12 @@ public string Image set { } get { + var fillingForm = FileUtility.CanWebRestrictedEditing(_configuration.Document.Title); + return _configuration.EditorType == EditorType.Embedded - ? null + || fillingForm + ? BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.Dark, !_configuration.EditorConfig.Customization.IsRetina)) : BaseCommonLinkUtility.GetFullAbsolutePath(TenantLogoHelper.GetLogo(WhiteLabelLogoTypeEnum.DocsEditor, !_configuration.EditorConfig.Customization.IsRetina)); } } @@ -910,6 +915,7 @@ public string Url private BaseCommonLinkUtility BaseCommonLinkUtility { get; } private TenantLogoHelper TenantLogoHelper { get; } + public FileUtility FileUtility { get; } private SettingsManager SettingsManager { get; } } diff --git a/products/ASC.Files/Core/Services/DocumentService/DocumentServiceConnector.cs b/products/ASC.Files/Core/Services/DocumentService/DocumentServiceConnector.cs index 6e46227267e..8ec62a194d2 100644 --- a/products/ASC.Files/Core/Services/DocumentService/DocumentServiceConnector.cs +++ b/products/ASC.Files/Core/Services/DocumentService/DocumentServiceConnector.cs @@ -43,8 +43,10 @@ using Microsoft.Extensions.Options; -using Newtonsoft.Json; - +using Newtonsoft.Json; + +using static ASC.Web.Core.Files.DocumentService; + using CommandMethod = ASC.Web.Core.Files.DocumentService.CommandMethod; namespace ASC.Web.Files.Services.DocumentService @@ -94,8 +96,8 @@ public int GetConvertedUri(string documentUri, string toExtension, string documentRevisionId, string password, - Web.Core.Files.DocumentService.ThumbnailData thumbnail, - Web.Core.Files.DocumentService.SpreadsheetLayout spreadsheetLayout, + ThumbnailData thumbnail, + SpreadsheetLayout spreadsheetLayout, bool isAsync, out string convertedDocumentUri) { @@ -127,12 +129,12 @@ public bool Command(CommandMethod method, object fileId = null, string callbackUrl = null, string[] users = null, - Web.Core.Files.DocumentService.MetaData meta = null) + MetaData meta = null) { Logger.DebugFormat("DocService command {0} fileId '{1}' docKey '{2}' callbackUrl '{3}' users '{4}' meta '{5}'", method, fileId, docKeyForTrack, callbackUrl, users != null ? string.Join(", ", users) : null, JsonConvert.SerializeObject(meta)); try { - var result = Web.Core.Files.DocumentService.CommandRequest( + var commandResponse = CommandRequest( FileUtility, FilesLinkUtility.DocServiceCommandUrl, method, @@ -140,15 +142,14 @@ public bool Command(CommandMethod method, callbackUrl, users, meta, - FileUtility.SignatureSecret, - out var version); - - if (result == Web.Core.Files.DocumentService.CommandResultTypes.NoError) + FileUtility.SignatureSecret); + + if (commandResponse.Error == CommandResponse.ErrorTypes.NoError) { return true; } - Logger.ErrorFormat("DocService command response: '{0}'", result); + Logger.ErrorFormat("DocService command response: '{0}' {1}", commandResponse.Error, commandResponse.ErrorString); } catch (Exception e) { @@ -200,7 +201,7 @@ public string GetVersion() Logger.DebugFormat("DocService request version"); try { - var result = Web.Core.Files.DocumentService.CommandRequest( + var commandResponse = CommandRequest( FileUtility, FilesLinkUtility.DocServiceCommandUrl, CommandMethod.Version, @@ -208,15 +209,20 @@ public string GetVersion() null, null, null, - FileUtility.SignatureSecret, - out var version); - - if (result == Web.Core.Files.DocumentService.CommandResultTypes.NoError) - { - return version; - } - - Logger.ErrorFormat("DocService command response: '{0}'", result); + FileUtility.SignatureSecret); + + var version = commandResponse.Version; + if (string.IsNullOrEmpty(version)) + { + version = "0"; + } + + if (commandResponse.Error == CommandResponse.ErrorTypes.NoError) + { + return version; + } + + Logger.ErrorFormat("DocService command response: '{0}' {1}", commandResponse.Error, commandResponse.ErrorString); } catch (Exception e) { @@ -231,7 +237,7 @@ public void CheckDocServiceUrl() { try { - if (!Web.Core.Files.DocumentService.HealthcheckRequest(FilesLinkUtility.DocServiceHealthcheckUrl)) + if (!HealthcheckRequest(FilesLinkUtility.DocServiceHealthcheckUrl)) { throw new Exception("bad status"); } @@ -284,7 +290,7 @@ public void CheckDocServiceUrl() try { var key = GenerateRevisionId(Guid.NewGuid().ToString()); - Web.Core.Files.DocumentService.CommandRequest(FileUtility, FilesLinkUtility.DocServiceCommandUrl, CommandMethod.Version, key, null, null, null, FileUtility.SignatureSecret, out var version); + CommandRequest(FileUtility, FilesLinkUtility.DocServiceCommandUrl, CommandMethod.Version, key, null, null, null, FileUtility.SignatureSecret); } catch (Exception ex) { diff --git a/products/ASC.Files/Core/Services/DocumentService/DocumentServiceTracker.cs b/products/ASC.Files/Core/Services/DocumentService/DocumentServiceTracker.cs index 0727d70792e..1c0cfd18ff2 100644 --- a/products/ASC.Files/Core/Services/DocumentService/DocumentServiceTracker.cs +++ b/products/ASC.Files/Core/Services/DocumentService/DocumentServiceTracker.cs @@ -436,7 +436,7 @@ private TrackResponse ProcessSave(T fileId, TrackerData fileData) try { - file = EntryManager.SaveEditing(fileId, null, DocumentServiceConnector.ReplaceDocumentAdress(fileData.Url), null, string.Empty, string.Join("; ", comments), false, fileData.Encrypted, forcesaveType); + file = EntryManager.SaveEditing(fileId, null, DocumentServiceConnector.ReplaceDocumentAdress(fileData.Url), null, string.Empty, string.Join("; ", comments), false, fileData.Encrypted, forcesaveType, true); saveMessage = fileData.Status == TrackerStatus.MustSave || fileData.Status == TrackerStatus.ForceSave ? null : "Status " + fileData.Status; } catch (Exception ex) diff --git a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDeleteOperation.cs b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDeleteOperation.cs index 660ec462a07..fac64723aba 100644 --- a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDeleteOperation.cs +++ b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileDeleteOperation.cs @@ -249,7 +249,9 @@ private void DeleteFiles(IEnumerable fileIds, IServiceScope scope) { Error = ex.Message; Logger.Error(Error, ex); - } + } + + LinkDao.DeleteAllLink(file.ID.ToString()); } ProcessedFile(fileId); } diff --git a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileMoveCopyOperation.cs b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileMoveCopyOperation.cs index f1e5a875c98..be3f0ce6f72 100644 --- a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileMoveCopyOperation.cs +++ b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileMoveCopyOperation.cs @@ -242,7 +242,8 @@ private List> MoveOrCopyFolders(IServiceScope scope, List } } - if (FolderDao.UseRecursiveOperation(folder.ID, toFolderId)) + if (toFolder.ProviderId == folder.ProviderId // crossDao operation is always recursive + && FolderDao.UseRecursiveOperation(folder.ID, toFolderId)) { MoveOrCopyFiles(scope, FileDao.GetFiles(folder.ID), newFolder, copy); MoveOrCopyFolders(scope, FolderDao.GetFolders(folder.ID).Select(f => f.ID).ToList(), newFolder, copy); @@ -467,6 +468,10 @@ private List> MoveOrCopyFiles(IServiceScope scope, List f fileDao.SaveThumbnail(newFile, null); } + if (newFile.ProviderEntry) + { + LinkDao.DeleteAllLink(file.ID.ToString()); + } if (Equals(toFolderId.ToString(), DaoFolderId)) { @@ -522,7 +527,9 @@ private List> MoveOrCopyFiles(IServiceScope scope, List f } newFile.ThumbnailStatus = Thumbnail.Created; } - + + LinkDao.DeleteAllLink(newFile.ID.ToString()); + needToMark.Add(newFile); if (copy) @@ -550,7 +557,9 @@ private List> MoveOrCopyFiles(IServiceScope scope, List f } else { - FileDao.DeleteFile(file.ID); + FileDao.DeleteFile(file.ID); + + LinkDao.DeleteAllLink(file.ID.ToString()); if (file.RootFolderType != FolderType.USER) { diff --git a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileOperation.cs b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileOperation.cs index 982333dbba3..8fb2f090968 100644 --- a/products/ASC.Files/Core/Services/WCFService/FileOperations/FileOperation.cs +++ b/products/ASC.Files/Core/Services/WCFService/FileOperations/FileOperation.cs @@ -247,7 +247,9 @@ abstract class FileOperation : FileOperation where T : FileOperationData protected IFileDao FileDao { get; private set; } - protected ITagDao TagDao { get; private set; } + protected ITagDao TagDao { get; private set; } + + protected ILinkDao LinkDao { get; private set; } protected IProviderDao ProviderDao { get; private set; } @@ -299,7 +301,8 @@ public override void RunJob(DistributedTask _, CancellationToken cancellationTok FolderDao = daoFactory.GetFolderDao(); FileDao = daoFactory.GetFileDao(); - TagDao = daoFactory.GetTagDao(); + TagDao = daoFactory.GetTagDao(); + LinkDao = daoFactory.GetLinkDao(); ProviderDao = daoFactory.ProviderDao; FilesSecurity = fileSecurity; diff --git a/products/ASC.Files/Core/Utils/EntryManager.cs b/products/ASC.Files/Core/Utils/EntryManager.cs index fa830e93c44..7b6d3e5ffe3 100644 --- a/products/ASC.Files/Core/Utils/EntryManager.cs +++ b/products/ASC.Files/Core/Utils/EntryManager.cs @@ -891,9 +891,98 @@ public Guid FileLockedBy(T fileId, ITagDao tagDao) { return LockerManager.FileLockedBy(fileId, tagDao); } + + public File GetFillFormDraft(File sourceFile, out Folder folderIfNew) + { + folderIfNew = null; + if (sourceFile == null) return null; + + File linkedFile = null; + var fileDao = DaoFactory.GetFileDao(); + var sourceFileDao = DaoFactory.GetFileDao(); + var linkDao = DaoFactory.GetLinkDao(); + + var fileSecurity = FileSecurity; + + var linkedId = linkDao.GetLinked(sourceFile.ID.ToString()); + if (linkedId != null) + { + linkedFile = fileDao.GetFile(int.Parse(linkedId)); + if (linkedFile == null + || !fileSecurity.CanFillForms(linkedFile) + || FileLockedForMe(linkedFile.ID) + || linkedFile.RootFolderType == FolderType.TRASH) + { + linkDao.DeleteLink(sourceFile.ID.ToString()); + linkedFile = null; + } + } + + if (linkedFile == null) + { + var folderId = GlobalFolderHelper.FolderMy; + var folderDao = DaoFactory.GetFolderDao(); + folderIfNew = folderDao.GetFolder(folderId); + if (folderIfNew == null) throw new Exception(FilesCommonResource.ErrorMassage_FolderNotFound); + if (!fileSecurity.CanCreate(folderIfNew)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create); + + linkedFile = new File + { + Title = sourceFile.Title, + FolderID = folderIfNew.ID, + FileStatus = sourceFile.FileStatus, + ConvertedType = sourceFile.ConvertedType, + Comment = FilesCommonResource.CommentCreateFillFormDraft, + Encrypted = sourceFile.Encrypted, + }; + + using (var stream = sourceFileDao.GetFileStream(sourceFile)) + { + linkedFile.ContentLength = stream.CanSeek ? stream.Length : sourceFile.ContentLength; + linkedFile = fileDao.SaveFile(linkedFile, stream); + } + + FileMarker.MarkAsNew(linkedFile); + + linkDao.AddLink(sourceFile.ID.ToString(), linkedFile.ID.ToString()); + } + + return linkedFile; + } + + public bool CheckFillFormDraft(File linkedFile) + { + if (linkedFile == null) return false; + + var linkDao = DaoFactory.GetLinkDao(); + var sourceId = linkDao.GetSource(linkedFile.ID.ToString()); + var fileSecurity = FileSecurity; + + if (int.TryParse(sourceId, out var sId)) + { + return Check(sId); + } + + return Check(sourceId); + + bool Check(T1 sourceId) + { + var fileDao = DaoFactory.GetFileDao(); + var sourceFile = fileDao.GetFile(sourceId); + if (sourceFile == null + || !fileSecurity.CanFillForms(sourceFile) + || sourceFile.Access != FileShare.FillForms) + { + linkDao.DeleteLink(sourceId.ToString()); + + return false; + } + + return true; + } + } - - public File SaveEditing(T fileId, string fileExtension, string downloadUri, Stream stream, string doc, string comment = null, bool checkRight = true, bool encrypted = false, ForcesaveType? forcesave = null) + public File SaveEditing(T fileId, string fileExtension, string downloadUri, Stream stream, string doc, string comment = null, bool checkRight = true, bool encrypted = false, ForcesaveType? forcesave = null, bool keepLink = false) { var newExtension = string.IsNullOrEmpty(fileExtension) ? FileUtility.GetFileExtension(downloadUri) @@ -1024,6 +1113,13 @@ public File SaveEditing(T fileId, string fileExtension, string downloadUri else { file = fileDao.SaveFile(file, tmpStream); + } + if (!keepLink + || file.CreateBy != AuthContext.CurrentAccount.ID + || !file.IsFillFormDraft) + { + var linkDao = DaoFactory.GetLinkDao(); + linkDao.DeleteAllLink(file.ID.ToString()); } } @@ -1135,6 +1231,9 @@ public File UpdateToVersionFile(T fileId, int version, string doc = null, } newFile.ThumbnailStatus = Thumbnail.Created; } + + var linkDao = DaoFactory.GetLinkDao(); + linkDao.DeleteAllLink(newFile.ID.ToString()); FileMarker.MarkAsNew(newFile); @@ -1258,12 +1357,12 @@ public void MarkAsRecent(File file) //Long operation - public void DeleteSubitems(T parentId, IFolderDao folderDao, IFileDao fileDao) + public void DeleteSubitems(T parentId, IFolderDao folderDao, IFileDao fileDao, ILinkDao linkDao) { var folders = folderDao.GetFolders(parentId); foreach (var folder in folders) { - DeleteSubitems(folder.ID, folderDao, fileDao); + DeleteSubitems(folder.ID, folderDao, fileDao, linkDao); Logger.InfoFormat("Delete folder {0} in {1}", folder.ID, parentId); folderDao.DeleteFolder(folder.ID); @@ -1273,7 +1372,9 @@ public void DeleteSubitems(T parentId, IFolderDao folderDao, IFileDao f foreach (var file in files) { Logger.InfoFormat("Delete file {0} in {1}", file.ID, parentId); - fileDao.DeleteFile(file.ID); + fileDao.DeleteFile(file.ID); + + linkDao.DeleteAllLink(file.ID.ToString()); } } diff --git a/products/ASC.Files/Core/Utils/FileConverter.cs b/products/ASC.Files/Core/Utils/FileConverter.cs index 0be94472cf7..7764df6e89b 100644 --- a/products/ASC.Files/Core/Utils/FileConverter.cs +++ b/products/ASC.Files/Core/Utils/FileConverter.cs @@ -879,7 +879,11 @@ public File SaveConvertedFile(File file, string convertedFileUrl) throw new Exception(errorString); } - FilesMessageService.Send(newFile, MessageInitiator.DocsService, MessageAction.FileConverted, newFile.Title); + FilesMessageService.Send(newFile, MessageInitiator.DocsService, MessageAction.FileConverted, newFile.Title); + + var linkDao = DaoFactory.GetLinkDao(); + linkDao.DeleteAllLink(file.ID.ToString()); + FileMarker.MarkAsNew(newFile); var tagDao = DaoFactory.GetTagDao(); diff --git a/products/ASC.Files/Core/Utils/FileUploader.cs b/products/ASC.Files/Core/Utils/FileUploader.cs index dc8ed2e5c5f..b42ae898d6c 100644 --- a/products/ASC.Files/Core/Utils/FileUploader.cs +++ b/products/ASC.Files/Core/Utils/FileUploader.cs @@ -127,7 +127,10 @@ public File Exec(T folderId, string title, long contentLength, Stream data var file = VerifyFileUpload(folderId, title, contentLength, !createNewIfExist); var dao = DaoFactory.GetFileDao(); - file = dao.SaveFile(file, data); + file = dao.SaveFile(file, data); + + var linkDao = DaoFactory.GetLinkDao(); + linkDao.DeleteAllLink(file.ID.ToString()); FileMarker.MarkAsNew(file); @@ -301,7 +304,10 @@ public ChunkedUploadSession UploadChunk(string uploadId, Stream stream, lo dao.UploadChunk(uploadSession, stream, chunkLength); if (uploadSession.BytesUploaded == uploadSession.BytesTotal) - { + { + var linkDao = DaoFactory.GetLinkDao(); + linkDao.DeleteAllLink(uploadSession.File.ID.ToString()); + FileMarker.MarkAsNew(uploadSession.File); ChunkedUploadSessionHolder.RemoveSession(uploadSession); } diff --git a/products/ASC.Files/Server/Controllers/FilesController.cs b/products/ASC.Files/Server/Controllers/FilesController.cs index c3da2caf8bc..2c544260c16 100644 --- a/products/ASC.Files/Server/Controllers/FilesController.cs +++ b/products/ASC.Files/Server/Controllers/FilesController.cs @@ -49,6 +49,7 @@ using ASC.Web.Core.Files; using ASC.Web.Files.Classes; using ASC.Web.Files.Configuration; +using ASC.Web.Files.Core.Compress; using ASC.Web.Files.Helpers; using ASC.Web.Files.Services.DocumentService; using ASC.Web.Files.Services.WCFService; @@ -97,6 +98,7 @@ public class FilesController : ControllerBase private ProductEntryPoint ProductEntryPoint { get; } private TenantManager TenantManager { get; } private FileUtility FileUtility { get; } + private FileConverter FileConverter { get; } /// /// @@ -125,7 +127,8 @@ public FilesController( ProductEntryPoint productEntryPoint, TenantManager tenantManager, FileUtility fileUtility, - ConsumerFactory consumerFactory) + ConsumerFactory consumerFactory, + FileConverter fileConverter) { FilesControllerHelperString = filesControllerHelperString; FilesControllerHelperInt = filesControllerHelperInt; @@ -150,6 +153,7 @@ public FilesController( ProductEntryPoint = productEntryPoint; TenantManager = tenantManager; FileUtility = fileUtility; + FileConverter = fileConverter; } [Read("info")] @@ -2181,13 +2185,13 @@ public bool DisplayTemplatesFromForm([FromForm] DisplayModel model) /// Settings /// [Update(@"settings/downloadtargz")] - public bool ChangeDownloadZipFromBody([FromBody] DisplayModel model) + public ICompress ChangeDownloadZipFromBody([FromBody] DisplayModel model) { return FileStorageService.ChangeDownloadTarGz(model.Set); } [Update(@"settings/downloadtargz")] - public bool ChangeDownloadZipFromForm([FromForm] DisplayModel model) + public ICompress ChangeDownloadZipFromForm([FromForm] DisplayModel model) { return FileStorageService.ChangeDownloadTarGz(model.Set); } @@ -2233,6 +2237,32 @@ public IEnumerable CreateThumbnailsFromForm([FromForm][ModelBinder( return FileStorageService.CreateThumbnails(model.FileIds.ToList()); } + [Create("masterform/{fileId}/checkfillformdraft")] + public object CheckFillFormDraftFromBody(string fileId, [FromBody] CheckFillFormDraftModel model) + { + return FilesControllerHelperString.CheckFillFormDraft(fileId, model.Version, model.Doc, !model.RequestEmbedded, model.RequestView); + } + + [Create("masterform/{fileId}/checkfillformdraft")] + [Consumes("application/x-www-form-urlencoded")] + public object CheckFillFormDraftFromForm(string fileId, [FromForm] CheckFillFormDraftModel model) + { + return FilesControllerHelperString.CheckFillFormDraft(fileId, model.Version, model.Doc, !model.RequestEmbedded, model.RequestView); + } + + [Create("masterform/{fileId:int}/checkfillformdraft")] + public object CheckFillFormDraftFromBody(int fileId, [FromBody] CheckFillFormDraftModel model) + { + return FilesControllerHelperInt.CheckFillFormDraft(fileId, model.Version, model.Doc, !model.RequestEmbedded, model.RequestView); + } + + [Create("masterform/{fileId:int}/checkfillformdraft")] + [Consumes("application/x-www-form-urlencoded")] + public object CheckFillFormDraftFromForm(int fileId, [FromForm] CheckFillFormDraftModel model) + { + return FilesControllerHelperInt.CheckFillFormDraft(fileId, model.Version, model.Doc, !model.RequestEmbedded, model.RequestView); + } + public IEnumerable CheckDocServiceUrl(CheckDocServiceUrlModel model) { FilesLinkUtility.DocServiceUrl = model.DocServiceUrl; diff --git a/products/ASC.Files/Server/Controllers/PrivacyRoomController.cs b/products/ASC.Files/Server/Controllers/PrivacyRoomController.cs index 3132782ae86..da6e06d7d34 100644 --- a/products/ASC.Files/Server/Controllers/PrivacyRoomController.cs +++ b/products/ASC.Files/Server/Controllers/PrivacyRoomController.cs @@ -87,14 +87,14 @@ public PrivacyRoomController( /// /// false [Update("keys")] - public object SetKeysFromBody([FromBody]PrivacyRoomModel model) + public object SetKeysFromBody([FromBody] PrivacyRoomModel model) { return SetKeys(model); } [Update("keys")] [Consumes("application/x-www-form-urlencoded")] - public object SetKeysFromForm([FromForm]PrivacyRoomModel model) + public object SetKeysFromForm([FromForm] PrivacyRoomModel model) { return SetKeys(model); } @@ -108,7 +108,7 @@ private object SetKeys(PrivacyRoomModel model) var keyPair = EncryptionKeyPairHelper.GetKeyPair(); if (keyPair != null) { - if (!string.IsNullOrEmpty(keyPair.PublicKey)) + if (!string.IsNullOrEmpty(keyPair.PublicKey) && !model.Update) { return new { isset = true }; } @@ -179,14 +179,14 @@ public bool PrivacyRoom() /// /// false [Update("")] - public bool SetPrivacyRoomFromBody([FromBody]PrivacyRoomModel model) + public bool SetPrivacyRoomFromBody([FromBody] PrivacyRoomModel model) { return SetPrivacyRoom(model); } [Update("")] [Consumes("application/x-www-form-urlencoded")] - public bool SetPrivacyRoomFromForm([FromForm]PrivacyRoomModel model) + public bool SetPrivacyRoomFromForm([FromForm] PrivacyRoomModel model) { return SetPrivacyRoom(model); } diff --git a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs index a357ffd3434..a2490c3cb46 100644 --- a/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs +++ b/products/ASC.Files/Server/Helpers/FilesControllerHelper.cs @@ -424,6 +424,11 @@ public IEnumerable> CheckConversion(T fileId, bool start, }); } + public string CheckFillFormDraft(T fileId, int version, string doc, bool editPossible, bool view) + { + return FileStorageService.CheckFillFormDraft(fileId, version, doc, editPossible, view); + } + public IEnumerable DeleteFolder(T folderId, bool deleteAfter, bool immediately) { return FileStorageService.DeleteFolder("delete", folderId, false, deleteAfter, immediately) diff --git a/products/ASC.Files/Service/Thumbnail/Builder.cs b/products/ASC.Files/Service/Thumbnail/Builder.cs index e402ac4129a..42682583218 100644 --- a/products/ASC.Files/Service/Thumbnail/Builder.cs +++ b/products/ASC.Files/Service/Thumbnail/Builder.cs @@ -261,14 +261,14 @@ private bool GetThumbnailUrl(File file, string toExtension, out string url) FitToWidth = 1, Headings = false, GridLines = false, - Margins = new DocumentService.Margins + Margins = new DocumentService.SpreadsheetLayout.LayoutMargins { Top = "0mm", Right = "0mm", Bottom = "0mm", Left = "0mm" }, - PageSize = new DocumentService.PageSize + PageSize = new DocumentService.SpreadsheetLayout.LayoutPageSize { Width = (config.ThumbnaillWidth * 1.5) + "mm", // 192 * 1.5 = "288mm", Height = (config.ThumbnaillHeight * 1.5) + "mm" // 128 * 1.5 = "192mm" diff --git a/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs b/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs index 0ed5122b0ea..a030440573f 100644 --- a/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs +++ b/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs @@ -32,7 +32,7 @@ public static ThumbnailSettings GetInstance(ConfigurationExtension configuration result.ServerRoot = cfg.ServerRoot ?? "http://localhost/"; result.LaunchFrequency = cfg.LaunchFrequency != 0 ? cfg.LaunchFrequency : 1; result.ConnectionStringName = cfg.ConnectionStringName ?? "default"; - result.Formats = cfg.Formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico"; + result.Formats = cfg.Formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docxf|.oform|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico"; result.SqlMaxResults = cfg.SqlMaxResults != 0 ? cfg.SqlMaxResults : 1000; result.MaxDegreeOfParallelism = cfg.MaxDegreeOfParallelism != 0 ? cfg.MaxDegreeOfParallelism : 10; result.AvailableFileSize = cfg.AvailableFileSize ?? 100L * 1024L * 1024L; diff --git a/web/ASC.Web.Api/Controllers/AuthenticationController.cs b/web/ASC.Web.Api/Controllers/AuthenticationController.cs index b2ea929c69a..191d4659c28 100644 --- a/web/ASC.Web.Api/Controllers/AuthenticationController.cs +++ b/web/ASC.Web.Api/Controllers/AuthenticationController.cs @@ -178,8 +178,13 @@ public AuthenticationTokenData AuthenticateMeFromForm([FromForm] AuthModel auth) [Read("logout")]// temp fix public void Logout() { + if (SecurityContext.IsAuthenticated) + CookiesManager.ResetUserCookie(SecurityContext.CurrentAccount.ID); + CookiesManager.ClearCookies(CookiesType.AuthKey); CookiesManager.ClearCookies(CookiesType.SocketIO); + + SecurityContext.Logout(); } [Create("confirm", false)] diff --git a/web/ASC.Web.Api/Controllers/PortalController.cs b/web/ASC.Web.Api/Controllers/PortalController.cs index a223657f812..28d61c3d8cc 100644 --- a/web/ASC.Web.Api/Controllers/PortalController.cs +++ b/web/ASC.Web.Api/Controllers/PortalController.cs @@ -15,6 +15,7 @@ using ASC.Web.Api.Models; using ASC.Web.Api.Routing; using ASC.Web.Core; +using ASC.Web.Core.Files; using ASC.Web.Core.Mobile; using ASC.Web.Core.Utility; using ASC.Web.Studio.Core; @@ -49,11 +50,12 @@ public class PortalController : ControllerBase private SettingsManager SettingsManager { get; } private IMobileAppInstallRegistrator MobileAppInstallRegistrator { get; } private IConfiguration Configuration { get; set; } - public CoreBaseSettings CoreBaseSettings { get; } - public LicenseReader LicenseReader { get; } - public SetupInfo SetupInfo { get; } + private CoreBaseSettings CoreBaseSettings { get; } + private LicenseReader LicenseReader { get; } + private SetupInfo SetupInfo { get; } + private DocumentServiceLicense DocumentServiceLicense { get; } private TenantExtra TenantExtra { get; set; } - public ILog Log { get; } + private ILog Log { get; } public PortalController( @@ -73,7 +75,8 @@ public PortalController( IConfiguration configuration, CoreBaseSettings coreBaseSettings, LicenseReader licenseReader, - SetupInfo setupInfo + SetupInfo setupInfo, + DocumentServiceLicense documentServiceLicense ) { Log = options.CurrentValue; @@ -92,6 +95,7 @@ SetupInfo setupInfo CoreBaseSettings = coreBaseSettings; LicenseReader = licenseReader; SetupInfo = setupInfo; + DocumentServiceLicense = documentServiceLicense; TenantExtra = tenantExtra; } @@ -148,7 +152,9 @@ public object GetTenantExtra() enableTariffPage = //TenantExtra.EnableTarrifSettings - think about hide-settings for opensource (!CoreBaseSettings.Standalone || !string.IsNullOrEmpty(LicenseReader.LicensePath)) && string.IsNullOrEmpty(SetupInfo.AmiMetaUrl) - && !CoreBaseSettings.CustomMode + && !CoreBaseSettings.CustomMode, + DocServerUserQuota = DocumentServiceLicense.GetLicenseQuota(), + DocServerLicense = DocumentServiceLicense.GetLicense() }; } @@ -166,7 +172,7 @@ public double GetUsedSpace() [Read("userscount")] public long GetUsersCount() { - return UserManager.GetUserNames(EmployeeStatus.Active).Count(); + return CoreBaseSettings.Personal ? 1 : UserManager.GetUserNames(EmployeeStatus.Active).Count(); } [Read("tariff")] @@ -234,7 +240,7 @@ public void MarkPresentAsReaded() } [Create("mobile/registration")] - public void RegisterMobileAppInstallFromBody([FromBody]MobileAppModel model) + public void RegisterMobileAppInstallFromBody([FromBody] MobileAppModel model) { var currentUser = UserManager.GetUsers(SecurityContext.CurrentAccount.ID); MobileAppInstallRegistrator.RegisterInstall(currentUser.Email, model.Type); @@ -242,7 +248,7 @@ public void RegisterMobileAppInstallFromBody([FromBody]MobileAppModel model) [Create("mobile/registration")] [Consumes("application/x-www-form-urlencoded")] - public void RegisterMobileAppInstallFromForm([FromForm]MobileAppModel model) + public void RegisterMobileAppInstallFromForm([FromForm] MobileAppModel model) { var currentUser = UserManager.GetUsers(SecurityContext.CurrentAccount.ID); MobileAppInstallRegistrator.RegisterInstall(currentUser.Email, model.Type); diff --git a/web/ASC.Web.Api/Controllers/SettingsController.cs b/web/ASC.Web.Api/Controllers/SettingsController.cs index 45ed1f08b59..b434eb30184 100644 --- a/web/ASC.Web.Api/Controllers/SettingsController.cs +++ b/web/ASC.Web.Api/Controllers/SettingsController.cs @@ -2119,7 +2119,7 @@ public List GetLicensorData() result.Add(instance); - if (!instance.IsDefault(CoreSettings) && !instance.GetIsLicensor(TenantManager, CoreSettings)) + if (!instance.IsDefault(CoreSettings) && !instance.IsLicensor) { result.Add(instance.GetDefault(ServiceProvider) as CompanyWhiteLabelSettings); } @@ -2638,7 +2638,7 @@ private bool SaveCompanyWhiteLabelSettings(CompanyWhiteLabelSettingsWrapper comp DemandRebrandingPermission(); - companyWhiteLabelSettingsWrapper.Settings.IsLicensorSetting = false; //TODO: CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Branding && settings.IsLicensor + companyWhiteLabelSettingsWrapper.Settings.IsLicensor = false; //TODO: CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Branding && settings.IsLicensor SettingsManager.SaveForDefaultTenant(companyWhiteLabelSettingsWrapper.Settings); return true; @@ -2863,7 +2863,13 @@ private bool SaveAuthKeys(AuthServiceModel model) changed = true; } } - if (validateKeyProvider != null && !validateKeyProvider.ValidateKeys() && !consumer.All(r => string.IsNullOrEmpty(r.Value))) + + //TODO: Consumer implementation required (Bug 50606) + var allPropsIsEmpty = consumer.GetType() == typeof(SmscProvider) + ? consumer.ManagedKeys.All(key => string.IsNullOrEmpty(consumer[key])) + : consumer.All(r => string.IsNullOrEmpty(r.Value)); + + if (validateKeyProvider != null && !validateKeyProvider.ValidateKeys() && !allPropsIsEmpty) { consumer.Clear(); throw new ArgumentException(Resource.ErrorBadKeys); diff --git a/web/ASC.Web.Api/Models/QuotaWrapper.cs b/web/ASC.Web.Api/Models/QuotaWrapper.cs index c7a30f3b84e..8f53c1eeaac 100644 --- a/web/ASC.Web.Api/Models/QuotaWrapper.cs +++ b/web/ASC.Web.Api/Models/QuotaWrapper.cs @@ -112,9 +112,9 @@ public QuotaWrapper( StorageSize = (ulong)Math.Max(0, quota.MaxTotalSize); UsedSize = (ulong)Math.Max(0, quotaRows.Sum(r => r.Counter)); - MaxUsersCount = TenantExtra.GetTenantQuota().ActiveUsers; + MaxUsersCount = quota.ActiveUsers; UsersCount = coreBaseSettings.Personal ? 1 : TenantStatisticsProvider.GetUsersCount(); - MaxVisitors = coreBaseSettings.Standalone ? -1 : constants.CoefficientOfVisitors * TenantExtra.GetTenantQuota().ActiveUsers; + MaxVisitors = coreBaseSettings.Standalone ? -1 : constants.CoefficientOfVisitors * quota.ActiveUsers; VisitorsCount = coreBaseSettings.Personal ? 0 : TenantStatisticsProvider.GetVisitorsCount(); StorageUsage = quotaRows diff --git a/web/ASC.Web.Core/Files/DocumentService.cs b/web/ASC.Web.Core/Files/DocumentService.cs index 2c19a8e71d0..a22ba333c11 100644 --- a/web/ASC.Web.Core/Files/DocumentService.cs +++ b/web/ASC.Web.Core/Files/DocumentService.cs @@ -40,7 +40,9 @@ using ASC.Common.Web; using ASC.Core; +using ASC.Core.Billing; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace ASC.Web.Core.Files @@ -233,15 +235,14 @@ public static int GetConvertedUri( /// Secret key to generate the token /// server version /// Response - public static CommandResultTypes CommandRequest(FileUtility fileUtility, + public static CommandResponse CommandRequest(FileUtility fileUtility, string documentTrackerUrl, CommandMethod method, string documentRevisionId, string callbackUrl, string[] users, MetaData meta, - string signatureSecret, - out string version) + string signatureSecret) { var request = (HttpWebRequest)WebRequest.Create(documentTrackerUrl); request.Method = "POST"; @@ -302,18 +303,20 @@ public static CommandResultTypes CommandRequest(FileUtility fileUtility, dataResponse = reader.ReadToEnd(); } - var jResponse = JObject.Parse(dataResponse); try { - version = jResponse.Value("version"); + var commandResponse = JsonConvert.DeserializeObject(dataResponse); + return commandResponse; } - catch (Exception) + catch (Exception ex) { - version = "0"; + return new CommandResponse + { + Error = CommandResponse.ErrorTypes.ParseError, + ErrorString = ex.Message + }; } - - return (CommandResultTypes)jResponse.Value("error"); } public static string DocbuilderRequest( @@ -439,18 +442,109 @@ public enum CommandMethod Version, ForceSave, //not used Meta, + License } - public enum CommandResultTypes + [Serializable] + [DebuggerDisplay("{Key}")] + public class CommandResponse { - NoError = 0, - DocumentIdError = 1, - ParseError = 2, - UnknownError = 3, - NotModify = 4, - UnknownCommand = 5, - Token = 6, - TokenExpire = 7, + [JsonPropertyName("error")] + public ErrorTypes Error { get; set; } + + [JsonPropertyName("errorString")] + public string ErrorString { get; set; } + + [JsonPropertyName("key")] + public string Key { get; set; } + + [JsonPropertyName("license")] + public License License { get; set; } + + [JsonPropertyName("server")] + public ServerInfo Server { get; set; } + + [JsonPropertyName("quota")] + public QuotaInfo Quota { get; set; } + + [JsonPropertyName("version")] + public string Version { get; set; } + + public enum ErrorTypes + { + NoError = 0, + DocumentIdError = 1, + ParseError = 2, + UnknownError = 3, + NotModify = 4, + UnknownCommand = 5, + Token = 6, + TokenExpire = 7, + } + + [Serializable] + [DebuggerDisplay("{BuildVersion}")] + public class ServerInfo + { + [JsonPropertyName("buildDate")] + public DateTime BuildDate { get; set; } + + [JsonPropertyName("buildNumber")] + public int buildNumber { get; set; } + + [JsonPropertyName("buildVersion")] + public string BuildVersion { get; set; } + + [JsonPropertyName("packageType")] + public PackageTypes PackageType { get; set; } + + [JsonPropertyName("resultType")] + public ResultTypes ResultType { get; set; } + + [JsonPropertyName("workersCount")] + public int WorkersCount { get; set; } + + public enum PackageTypes + { + OpenSource = 0, + IntegrationEdition = 1, + DeveloperEdition = 2 + } + + public enum ResultTypes + { + Error = 1, + Expired = 2, + Success = 3, + UnknownUser = 4, + Connections = 5, + ExpiredTrial = 6, + SuccessLimit = 7, + UsersCount = 8, + ConnectionsOS = 9, + UsersCountOS = 10, + ExpiredLimited = 11 + } + } + + [Serializable] + [DataContract(Name = "Quota", Namespace = "")] + public class QuotaInfo + { + [JsonPropertyName("users")] + public List Users { get; set; } + + [Serializable] + [DebuggerDisplay("{UserId} ({Expire})")] + public class User + { + [JsonPropertyName("userid")] + public string UserId { get; set; } + + [JsonPropertyName("expire")] + public DateTime Expire { get; set; } + } + } } [Serializable] @@ -535,38 +629,39 @@ public class SpreadsheetLayout public bool GridLines { get; set; } [JsonPropertyName("margins")] - public Margins Margins { get; set; } + public LayoutMargins Margins { get; set; } [JsonPropertyName("pageSize")] - public PageSize PageSize { get; set; } - } + public LayoutPageSize PageSize { get; set; } - [Serializable] - [DebuggerDisplay("Margins {Top} {Right} {Bottom} {Left}")] - public class Margins - { - [JsonPropertyName("left")] - public string Left { get; set; } - [JsonPropertyName("right")] - public string Right { get; set; } + [Serializable] + [DebuggerDisplay("Margins {Top} {Right} {Bottom} {Left}")] + public class LayoutMargins + { + [JsonPropertyName("left")] + public string Left { get; set; } - [JsonPropertyName("top")] - public string Top { get; set; } + [JsonPropertyName("right")] + public string Right { get; set; } - [JsonPropertyName("bottom")] - public string Bottom { get; set; } - } + [JsonPropertyName("top")] + public string Top { get; set; } - [Serializable] - [DebuggerDisplay("PageSize {Width} {Height}")] - public class PageSize - { - [JsonPropertyName("height")] - public string Height { get; set; } + [JsonPropertyName("bottom")] + public string Bottom { get; set; } + } - [JsonPropertyName("width")] - public string Width { get; set; } + [Serializable] + [DebuggerDisplay("PageSize {Width} {Height}")] + public class LayoutPageSize + { + [JsonPropertyName("height")] + public string Height { get; set; } + + [JsonPropertyName("width")] + public string Width { get; set; } + } } [Serializable] diff --git a/web/ASC.Web.Core/Files/DocumentServiceLicense.cs b/web/ASC.Web.Core/Files/DocumentServiceLicense.cs new file mode 100644 index 00000000000..64b87e03865 --- /dev/null +++ b/web/ASC.Web.Core/Files/DocumentServiceLicense.cs @@ -0,0 +1,97 @@ +/* + * + * (c) Copyright Ascensio System Limited 2010-2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +using System; +using System.Collections.Generic; + +using ASC.Common; +using ASC.Common.Caching; +using ASC.Core; +using ASC.Core.Billing; + +using static ASC.Web.Core.Files.DocumentService; + +namespace ASC.Web.Core.Files +{ + [Scope] + public class DocumentServiceLicense + { + private static readonly TimeSpan CACHE_EXPIRATION = TimeSpan.FromMinutes(15); + + private ICache Cache { get; } + public CoreBaseSettings CoreBaseSettings { get; } + private FilesLinkUtility FilesLinkUtility { get; } + private FileUtility FileUtility { get; } + + public DocumentServiceLicense( + ICache cache, + CoreBaseSettings coreBaseSettings, + FilesLinkUtility filesLinkUtility, + FileUtility fileUtility) + { + Cache = cache; + CoreBaseSettings = coreBaseSettings; + FilesLinkUtility = filesLinkUtility; + FileUtility = fileUtility; + } + + private CommandResponse GetDocumentServiceLicense() + { + if (!CoreBaseSettings.Standalone) return null; + if (string.IsNullOrEmpty(FilesLinkUtility.DocServiceCommandUrl)) return null; + + var cacheKey = "DocumentServiceLicense"; + var commandResponse = Cache.Get(cacheKey); + if (commandResponse == null) + { + commandResponse = DocumentService.CommandRequest( + FileUtility, + FilesLinkUtility.DocServiceCommandUrl, + DocumentService.CommandMethod.License, + null, + null, + null, + null, + FileUtility.SignatureSecret); + Cache.Insert(cacheKey, commandResponse, DateTime.UtcNow.Add(CACHE_EXPIRATION)); + } + + return commandResponse; + } + + public Dictionary GetLicenseQuota() + { + var commandResponse = GetDocumentServiceLicense(); + if (commandResponse == null + || commandResponse.Quota == null + || commandResponse.Quota.Users == null) + return null; + + var result = new Dictionary(); + commandResponse.Quota.Users.ForEach(user => result.Add(user.UserId, user.Expire)); + return result; + } + + public License GetLicense() + { + var commandResponse = GetDocumentServiceLicense(); + if (commandResponse == null) + return null; + + return commandResponse.License; + } + } +} \ No newline at end of file diff --git a/web/ASC.Web.Core/Files/FileUtility.cs b/web/ASC.Web.Core/Files/FileUtility.cs index 58849013b2e..8a4435c75c3 100644 --- a/web/ASC.Web.Core/Files/FileUtility.cs +++ b/web/ASC.Web.Core/Files/FileUtility.cs @@ -409,7 +409,8 @@ public List ExtsCoAuthoring ".html", ".htm", ".mht", ".pdf", ".djvu", ".fb2", ".epub", ".xps", ".doct", ".docy", - ".gdoc" + ".gdoc", + ".docxf", ".oform" }; public static readonly List ExtsTemplate = new List @@ -429,6 +430,7 @@ public Dictionary InternalExtension }; } + public string MasterFormExtension { get => Configuration["files:docservice:internal-form"] ?? ".docxf"; } public enum CsvDelimiter { None = 0, diff --git a/web/ASC.Web.Core/Notify/StudioNotifyService.cs b/web/ASC.Web.Core/Notify/StudioNotifyService.cs index 4a88999ee95..b95dc80352a 100644 --- a/web/ASC.Web.Core/Notify/StudioNotifyService.cs +++ b/web/ASC.Web.Core/Notify/StudioNotifyService.cs @@ -241,7 +241,7 @@ public void SendMailboxCreated(List toEmails, string username, string ad } public void SendMailboxCreated(List toEmails, string username, string address, string server, - string encyption, int portImap, int portSmtp, string login) + string encyption, int portImap, int portSmtp, string login, bool skipSettings = false) { var tags = new List { @@ -249,8 +249,6 @@ public void SendMailboxCreated(List toEmails, string username, string ad new TagValue(Tags.Address, address ?? string.Empty) }; - var skipSettings = string.IsNullOrEmpty(server); - if (!skipSettings) { var link = string.Format("{0}/addons/mail/#accounts/changepwd={1}", @@ -781,11 +779,13 @@ public void SendInvitePersonal(string email, string additionalMember = "") var lang = CoreBaseSettings.CustomMode ? "ru-RU" - : Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; + : Thread.CurrentThread.CurrentUICulture.Name; + + var culture = SetupInfo.GetPersonalCulture(lang); var confirmUrl = CommonLinkUtility.GetConfirmationUrl(email, ConfirmType.EmpInvite, (int)EmployeeType.User) + "&emplType=" + (int)EmployeeType.User - + "&lang=" + lang + + "&lang=" + culture.Key + additionalMember; client.SendNoticeToAsync( diff --git a/web/ASC.Web.Core/Notify/StudioNotifyServiceSender.cs b/web/ASC.Web.Core/Notify/StudioNotifyServiceSender.cs index 2d03e70a641..197177bbfc7 100644 --- a/web/ASC.Web.Core/Notify/StudioNotifyServiceSender.cs +++ b/web/ASC.Web.Core/Notify/StudioNotifyServiceSender.cs @@ -127,7 +127,10 @@ public void RegisterSendMethod() { if (coreBaseSettings.Personal) { - WorkContext.RegisterSendMethod(SendLettersPersonal, cron); + if (!coreBaseSettings.CustomMode) + { + WorkContext.RegisterSendMethod(SendLettersPersonal, cron); + } } else { diff --git a/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs b/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs index 8498d40d281..1963ea9430a 100644 --- a/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs +++ b/web/ASC.Web.Core/Notify/StudioPeriodicNotify.cs @@ -291,7 +291,7 @@ public void SendSaasLetters(string senderName, DateTime scheduleDate) #region 5 days before SAAS TRIAL ends to admins - else if (dueDateIsNotMax && dueDate.AddDays(-5) == nowDate) + else if (!coreBaseSettings.CustomMode && dueDateIsNotMax && dueDate.AddDays(-5) == nowDate) { toadmins = true; action = Actions.SaasAdminTrialWarningBefore5V115; @@ -1023,7 +1023,7 @@ public void SendPersonalLetters(string senderName, DateTime scheduleDate) case 28: action = Actions.PersonalAfterRegistration28; greenButtonText = () => WebstudioNotifyPatternResource.ButtonStartFreeTrial; - greenButtonUrl = "https://www.onlyoffice.com/download-commercial.aspx"; + greenButtonUrl = "https://www.onlyoffice.com/download-workspace.aspx"; break; default: continue; diff --git a/web/ASC.Web.Core/SetupInfo.cs b/web/ASC.Web.Core/SetupInfo.cs index 8d1194435f5..47d76ca0017 100644 --- a/web/ASC.Web.Core/SetupInfo.cs +++ b/web/ASC.Web.Core/SetupInfo.cs @@ -49,11 +49,14 @@ public class SetupInfo public string MetaImageURL { get; private set; } public string StatisticTrackURL { get; private set; } + public string DemoOrder { get; private set; } + public string RequestTraining { get; private set; } + public string ZendeskKey { get; private set; } public string UserVoiceURL { get; private set; } public string MainLogoURL { get; private set; } public string MainLogoMailTmplURL { get; private set; } public List EnabledCultures { get; private set; } - public List EnabledCulturesPersonal { get; set; } + private List EnabledCulturesPersonal { get; set; } public List> PersonalCultures { get; private set; } public decimal ExchangeRateRuble { get; private set; } public long MaxImageUploadSize { get; private set; } @@ -130,6 +133,9 @@ public SetupInfo(IConfiguration configuration) MetaImageURL = GetAppSettings("web.meta-image-url", "https://download.onlyoffice.com/assets/fb/fb_icon_325x325.jpg"); StatisticTrackURL = GetAppSettings("web.track-url", string.Empty); UserVoiceURL = GetAppSettings("web.uservoice", string.Empty); + DemoOrder = GetAppSettings("web.demo-order", string.Empty); + ZendeskKey = GetAppSettings("web.zendesk-key", string.Empty); + RequestTraining = GetAppSettings("web.request-training", string.Empty); MainLogoURL = GetAppSettings("web.logo.main", string.Empty); MainLogoMailTmplURL = GetAppSettings("web.logo.mail.tmpl", string.Empty); DownloadForDesktopUrl = GetAppSettings("web.download.for.desktop.url", "https://www.onlyoffice.com/desktop.aspx"); @@ -139,14 +145,15 @@ public SetupInfo(IConfiguration configuration) EnabledCultures = GetAppSettings("web:cultures", "en-US") .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Distinct() .Select(l => CultureInfo.GetCultureInfo(l.Trim())) .OrderBy(l => l.DisplayName) .ToList(); EnabledCulturesPersonal = GetAppSettings("web:cultures:personal", GetAppSettings("web:cultures", "en-US")) .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Distinct() .Select(l => CultureInfo.GetCultureInfo(l.Trim())) - .OrderBy(l => l.DisplayName) .ToList(); PersonalCultures = GetPersonalCultures(); diff --git a/web/ASC.Web.Core/WhiteLabel/CompanyWhiteLabelSettings.cs b/web/ASC.Web.Core/WhiteLabel/CompanyWhiteLabelSettings.cs index de57cbf28e9..1533346fa15 100644 --- a/web/ASC.Web.Core/WhiteLabel/CompanyWhiteLabelSettings.cs +++ b/web/ASC.Web.Core/WhiteLabel/CompanyWhiteLabelSettings.cs @@ -54,13 +54,7 @@ public class CompanyWhiteLabelSettings : ISettings public string Phone { get; set; } [JsonPropertyName("IsLicensor")] - public bool IsLicensorSetting { get; set; } - - public bool GetIsLicensor(TenantManager tenantManager, CoreSettings coreSettings) - { - return IsLicensorSetting - && (IsDefault(coreSettings) || tenantManager.GetTenantQuota(tenantManager.GetCurrentTenant().TenantId).Branding); - } + public bool IsLicensor { get; set; } public bool IsDefault(CoreSettings coreSettings) @@ -72,7 +66,7 @@ public bool IsDefault(CoreSettings coreSettings) Email == defaultSettings.Email && Address == defaultSettings.Address && Phone == defaultSettings.Phone && - IsLicensorSetting == defaultSettings.IsLicensorSetting; + IsLicensor == defaultSettings.IsLicensor; } #region ISettings Members From 99f73e8aeed60804706d76aa892b67fe13012b63 Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 09:53:41 +0300 Subject: [PATCH 006/395] Web: Files: Added translations for files dialog. --- products/ASC.Files/Client/public/locales/en/Article.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/products/ASC.Files/Client/public/locales/en/Article.json b/products/ASC.Files/Client/public/locales/en/Article.json index 52f49986880..887fd04514a 100644 --- a/products/ASC.Files/Client/public/locales/en/Article.json +++ b/products/ASC.Files/Client/public/locales/en/Article.json @@ -4,5 +4,6 @@ "NewPresentation": "New Presentation", "NewSpreadsheet": "New Spreadsheet", "UploadFiles": "Upload files", - "UploadFolder": "Upload folder" -} \ No newline at end of file + "UploadFolder": "Upload folder", + "CreateMasterFormFromFile": "Create Master Form from file" +} From e704f2f1271894a7540d005bd69e8c8dcc90e0fb Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 09:56:04 +0300 Subject: [PATCH 007/395] Web: Files: Added new foldersType, removed saving folder to store. --- .../panels/SelectFileDialog/ModalView.js | 14 +++++++ .../panels/SelectFileDialog/index.js | 37 +++++++++---------- .../panels/SelectFolderDialog/index.js | 35 +++++++++++++----- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js index 114ab481315..70269ca1fbe 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js @@ -20,6 +20,7 @@ const exceptSortedByTagsFolders = [ ]; const exceptTrashFolder = [FolderType.TRASH]; +const exceptPrivacyTrashFolders = [FolderType.Privacy, FolderType.TRASH]; class SelectFileDialogModalView extends React.Component { constructor(props) { super(props); @@ -72,6 +73,19 @@ class SelectFileDialogModalView extends React.Component { console.error(err); } + this.loadersCompletes(); + break; + case "exceptPrivacyTrashFolders": + try { + const foldersTree = await getFoldersTree(); + this.folderList = SelectFolderDialog.convertFolders( + foldersTree, + exceptPrivacyTrashFolders + ); + this.onSetSelectedFolder(); + } catch (err) { + console.error(err); + } this.loadersCompletes(); break; case "common": diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js index 27865aa444d..7eb3152ab5f 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js @@ -103,6 +103,7 @@ class SelectFileDialogBody extends React.Component { resetTreeFolders, setExpandedPanelKeys, setDefaultSelectedFolder, + setSelectedFolder, setFolderId, setFile, } = this.props; @@ -111,7 +112,7 @@ class SelectFileDialogBody extends React.Component { if (resetTreeFolders) { setExpandedPanelKeys(null); - setDefaultSelectedFolder(); + //setSelectedFolder(null); setFolderId(null); setFile(null); @@ -144,11 +145,11 @@ class SelectFileDialogBody extends React.Component { }; onSelectFolder = (id) => { - const { setFolderId } = this.props; + const { setFolderId, setExpandedPanelKeys } = this.props; if (id) { setFolderId(id); - + setExpandedPanelKeys([`${id}`]); this.setState({ selectedFolder: id, hasNextPage: true, @@ -184,7 +185,7 @@ class SelectFileDialogBody extends React.Component { }; loadNextPage = () => { - const { setSelectedNode, setSelectedFolder } = this.props; + //const { setSelectedNode, setSelectedFolder } = this.props; const { selectedFolder, page } = this.state; if (this._isLoadNextPage) return; @@ -202,17 +203,16 @@ class SelectFileDialogBody extends React.Component { ? this.state.filesList.concat(data.files) : data.files; - setSelectedNode([selectedFolder + ""]); - const newPathParts = SelectFolderDialog.convertPathParts( - data.pathParts - ); - - setSelectedFolder({ - folders: data.folders, - ...data.current, - pathParts: newPathParts, - ...{ new: data.new }, - }); + // const newPathParts = SelectFolderDialog.convertPathParts( //TODO: maybe need + // data.pathParts + // ); + // setSelectedNode([selectedFolder + ""]); + // setSelectedFolder({ + // folders: data.folders, + // ...data.current, + // pathParts: newPathParts, + // ...{ new: data.new }, + // }); this.setState({ hasNextPage: newFilesList.length < data.total, isNextPageLoading: false, @@ -321,6 +321,7 @@ SelectFileDialogBody.propTypes = { "third-party", "exceptSortedByTags", "exceptTrashFolder", + "exceptPrivacyTrashFolders", ]), folderId: PropTypes.string, withoutProvider: PropTypes.bool, @@ -351,10 +352,7 @@ const SelectFileDialogWrapper = inject( const { setSelectedNode, setExpandedPanelKeys } = treeFoldersStore; const { filter } = filesStore; - const { - setSelectedFolder, - toDefault: setDefaultSelectedFolder, - } = selectedFolderStore; + const { setSelectedFolder } = selectedFolderStore; return { storeFolderId, fileInfo, @@ -363,7 +361,6 @@ const SelectFileDialogWrapper = inject( setSelectedFolder, setSelectedNode, filter, - setDefaultSelectedFolder, setExpandedPanelKeys, }; } diff --git a/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/index.js b/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/index.js index 8b57ffee7f2..7ca3960ce93 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/index.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/index.js @@ -38,6 +38,7 @@ const exceptSortedByTagsFolders = [ ]; const exceptTrashFolder = [FolderType.TRASH]; +const exceptPrivacyTrashFolders = [FolderType.Privacy, FolderType.TRASH]; class SelectFolderModalDialog extends React.Component { constructor(props) { super(props); @@ -88,6 +89,7 @@ class SelectFolderModalDialog extends React.Component { id, selectedFolderId, } = this.props; + switch (foldersType) { case "exceptSortedByTags": try { @@ -115,6 +117,20 @@ class SelectFolderModalDialog extends React.Component { this.loadersCompletes(); } break; + case "exceptPrivacyTrashFolders": + try { + const foldersTree = await getFoldersTree(); + folderList = SelectFolderDialog.convertFolders( + foldersTree, + exceptPrivacyTrashFolders + ); + console.log("folderList", folderList); + this.setBaseSettings(); + } catch (err) { + console.error(err); + this.loadersCompletes(); + } + break; case "common": try { folderList = await SelectFolderDialog.getCommonFolders(); @@ -303,15 +319,14 @@ class SelectFolderModalDialog extends React.Component { setFolderObjectToTree = (id, data) => { const { setSelectedNode, setSelectedFolder } = this.props; - setSelectedNode([id + ""]); - - const newPathParts = SelectFolderDialog.convertPathParts(data.pathParts); - setSelectedFolder({ - folders: data.folders, - ...data.current, - pathParts: newPathParts, - ...{ new: data.new }, - }); + //setSelectedNode([id + ""]); + //const newPathParts = SelectFolderDialog.convertPathParts(data.pathParts); + // setSelectedFolder({ + // folders: data.folders, + // ...data.current, + // pathParts: newPathParts, + // ...{ new: data.new }, + // }); }; componentWillUnmount() { @@ -497,6 +512,7 @@ SelectFolderModalDialog.propTypes = { "third-party", "exceptSortedByTags", "exceptTrashFolder", + "exceptPrivacyTrashFolders", ]), displayType: PropTypes.oneOf(["aside", "modal"]), id: PropTypes.string, @@ -518,6 +534,7 @@ SelectFolderModalDialog.defaultProps = { zIndex: 310, withoutProvider: false, folderPath: "", + showButtons: false, }; const SelectFolderDialogWrapper = inject( From ebe35242c0a89c0647cff50431e9eb9d4393aac2 Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 09:59:40 +0300 Subject: [PATCH 008/395] Web: Components: Added new prop. --- packages/asc-web-components/modal-dialog/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/asc-web-components/modal-dialog/index.js b/packages/asc-web-components/modal-dialog/index.js index 51afdf9c4af..80cebd54435 100644 --- a/packages/asc-web-components/modal-dialog/index.js +++ b/packages/asc-web-components/modal-dialog/index.js @@ -182,6 +182,7 @@ class ModalDialog extends React.Component { zIndex={zIndex} contentPaddingBottom={contentPaddingBottom} className="modal-dialog-aside not-selectable" + withoutBodyScroll={removeScroll} > Date: Wed, 17 Nov 2021 10:13:58 +0300 Subject: [PATCH 009/395] Web: Files: Fixed aside panel. --- .../panels/SelectFileDialog/AsideView.js | 44 +++++++++---------- .../src/components/panels/StyledPanels.js | 31 +++---------- 2 files changed, 26 insertions(+), 49 deletions(-) diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js index 1defac253be..c71b3157207 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js @@ -14,6 +14,7 @@ import Button from "@appserver/components/button"; import Loaders from "@appserver/common/components/Loaders"; import Loader from "@appserver/components/loader"; import EmptyContainer from "../../EmptyContainer/EmptyContainer"; +import ModalDialog from "@appserver/components/modal-dialog"; const DISPLAY_TYPE = "aside"; const SelectFileDialogAsideView = ({ t, @@ -52,27 +53,22 @@ const SelectFileDialogAsideView = ({ return ( - - + + ); }; diff --git a/products/ASC.Files/Client/src/components/panels/StyledPanels.js b/products/ASC.Files/Client/src/components/panels/StyledPanels.js index de3e5b8e549..29644ebd824 100644 --- a/products/ASC.Files/Client/src/components/panels/StyledPanels.js +++ b/products/ASC.Files/Client/src/components/panels/StyledPanels.js @@ -659,36 +659,28 @@ const StyledSelectFolderPanel = styled.div` } `; const StyledSelectFilePanel = styled.div` + height: 100%; .select-file-dialog_empty-container { .ec-header { word-break: break-word; } } - ${(props) => - props.displayType === "aside" && - css` - height: 100%; - overflow: hidden; - `} - .select-file-dialog-modal_buttons { ${(props) => props.isHeaderChildren ? "margin-top: 40px" : "margin-top:20px"}; } .select-file-dialog_aside-body_wrapper { height: ${(props) => - props.isHeaderChildren ? "calc(100% - 260px);" : "calc(100% - 212px);"}; + props.isHeaderChildren ? "calc(100% - 147px);" : "calc(100% - 100px);"}; } - .select-file-dialog_aside-body_wrapper, + .select-folder-dialog_aside-body_wrapper { width: 320px; - padding: 0 16px; box-sizing: border-box; - } - .select-folder-dialog_aside-body_wrapper { height: 100%; } + .select-file-dialog_aside-children { ${(props) => props.isHeaderChildren && `padding-bottom: 16px;`} } @@ -697,19 +689,7 @@ const StyledSelectFilePanel = styled.div` height: 100%; width: 290px; } - .select-file-dialog_aside-header_title { - margin: 0px; - line-height: 56px; - max-width: 474px; - width: 400px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - .select-file-dialog_aside-header { - margin-bottom: 16px; - } - .select-file-dialog_aside-header, + .file-name { border-bottom: 1px solid #eceef1; } @@ -767,7 +747,6 @@ const StyledSelectFilePanel = styled.div` } .select-file-dialog-buttons-save { margin-right: 8px; - margin-left: 16px; } .select-file-modal-dialog-buttons-save { margin-right: 8px; From af55b39eabe7f1534094e2d07508a0467291b668 Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 11:47:00 +0300 Subject: [PATCH 010/395] Web: Files: Added select file dialog to the panels. --- .../src/components/FilesPanels/index.js | 29 ++++++++++++++++++- .../Client/src/components/panels/index.js | 2 ++ .../Client/src/store/DialogsStore.js | 9 ++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/products/ASC.Files/Client/src/components/FilesPanels/index.js b/products/ASC.Files/Client/src/components/FilesPanels/index.js index 84dde218d1c..646856a5dbb 100644 --- a/products/ASC.Files/Client/src/components/FilesPanels/index.js +++ b/products/ASC.Files/Client/src/components/FilesPanels/index.js @@ -1,4 +1,5 @@ import React from "react"; +import { useTranslation } from "react-i18next"; import { inject, observer } from "mobx-react"; import { SharingPanel, @@ -7,6 +8,7 @@ import { VersionHistoryPanel, ChangeOwnerPanel, NewFilesPanel, + SelectFileDialog, } from "../panels"; import { ThirdPartyMoveDialog, @@ -38,8 +40,14 @@ const Panels = (props) => { newFilesPanelVisible, conflictResolveDialogVisible, convertDialogVisible, + createMasterForm, + selectFileDialogVisible, + setSelectFileDialogVisible, } = props; - + const { t } = useTranslation("Article"); + const onClose = () => { + setSelectFileDialogVisible(false); + }; return [ uploadPanelVisible && , sharingPanelVisible && ( @@ -71,6 +79,18 @@ const Panels = (props) => { ), convertDialogVisible && , + selectFileDialogVisible && ( + + ), ]; }; @@ -93,6 +113,10 @@ export default inject( convertDialogVisible, connectItem, //TODO: + + createMasterForm, + selectFileDialogVisible, + setSelectFileDialogVisible, } = dialogsStore; const { uploadPanelVisible } = uploadDataStore; @@ -115,6 +139,9 @@ export default inject( newFilesPanelVisible, conflictResolveDialogVisible, convertDialogVisible, + selectFileDialogVisible, + createMasterForm, + setSelectFileDialogVisible, }; } )(observer(Panels)); diff --git a/products/ASC.Files/Client/src/components/panels/index.js b/products/ASC.Files/Client/src/components/panels/index.js index 5ef887cda9d..6e188212e26 100644 --- a/products/ASC.Files/Client/src/components/panels/index.js +++ b/products/ASC.Files/Client/src/components/panels/index.js @@ -7,6 +7,7 @@ import NewFilesPanel from "./NewFilesPanel"; import VersionHistoryPanel from "./VersionHistoryPanel"; import ChangeOwnerPanel from "./ChangeOwnerPanel"; import UploadPanel from "./UploadPanel"; +import SelectFileDialog from "./SelectFileDialog"; export { SharingPanel, @@ -18,4 +19,5 @@ export { VersionHistoryPanel, ChangeOwnerPanel, UploadPanel, + SelectFileDialog, }; diff --git a/products/ASC.Files/Client/src/store/DialogsStore.js b/products/ASC.Files/Client/src/store/DialogsStore.js index ba62650adb6..e12689b4d34 100644 --- a/products/ASC.Files/Client/src/store/DialogsStore.js +++ b/products/ASC.Files/Client/src/store/DialogsStore.js @@ -20,6 +20,7 @@ class DialogsStore { newFilesPanelVisible = false; conflictResolveDialogVisible = false; convertDialogVisible = false; + selectFileDialogVisible = false; removeItem = null; connectItem = null; @@ -170,6 +171,14 @@ class DialogsStore { setConvertItem = (item) => { this.convertItem = item; }; + + setSelectFileDialogVisible = (visible) => { + this.selectFileDialogVisible = visible; + }; + + createMasterForm = async (fileInfo) => { + console.log("fileInfo", fileInfo); + }; } export default DialogsStore; From b10201113976d94458329a591d2e74537652af99 Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 13:09:54 +0300 Subject: [PATCH 011/395] Web: Files: Added button mane prop. --- products/ASC.Files/Client/public/locales/en/Home.json | 3 ++- products/ASC.Files/Client/public/locales/ru/Home.json | 3 ++- .../ASC.Files/Client/src/components/FilesPanels/index.js | 5 +++-- .../src/components/panels/SelectFileDialog/AsideView.js | 7 ++++--- .../src/components/panels/SelectFileDialog/ModalView.js | 3 ++- .../Client/src/components/panels/SelectFileDialog/index.js | 3 +++ 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/products/ASC.Files/Client/public/locales/en/Home.json b/products/ASC.Files/Client/public/locales/en/Home.json index dc952d67b44..60cd9d74cac 100644 --- a/products/ASC.Files/Client/public/locales/en/Home.json +++ b/products/ASC.Files/Client/public/locales/en/Home.json @@ -81,5 +81,6 @@ "UnblockVersion": "Unblock/Check-in", "UploadToFolder": "Upload to folder", "ViewList": "List", - "ViewTiles": "Tiles" + "ViewTiles": "Tiles", + "Create": "Create" } diff --git a/products/ASC.Files/Client/public/locales/ru/Home.json b/products/ASC.Files/Client/public/locales/ru/Home.json index df5f60a9fd1..d5568d0cf23 100644 --- a/products/ASC.Files/Client/public/locales/ru/Home.json +++ b/products/ASC.Files/Client/public/locales/ru/Home.json @@ -81,5 +81,6 @@ "UnblockVersion": "Заблокировать/Разблокировать", "UploadToFolder": "Загрузить в папку", "ViewList": "Список", - "ViewTiles": "Плитки" + "ViewTiles": "Плитки", + "Create": "Создать" } diff --git a/products/ASC.Files/Client/src/components/FilesPanels/index.js b/products/ASC.Files/Client/src/components/FilesPanels/index.js index 646856a5dbb..75b57756b77 100644 --- a/products/ASC.Files/Client/src/components/FilesPanels/index.js +++ b/products/ASC.Files/Client/src/components/FilesPanels/index.js @@ -44,7 +44,7 @@ const Panels = (props) => { selectFileDialogVisible, setSelectFileDialogVisible, } = props; - const { t } = useTranslation("Article"); + const { t } = useTranslation(["Article", "Home"]); const onClose = () => { setSelectFileDialogVisible(false); }; @@ -88,7 +88,8 @@ const Panels = (props) => { onClose={onClose} foldersType="exceptPrivacyTrashFolders" isDocumentsOnly - headerName={t("CreateMasterFormFromFile")} + headerName={t("Article:CreateMasterFormFromFile")} + buttonName={t("Home:Create")} /> ), ]; diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js index c71b3157207..0f393854656 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js @@ -44,6 +44,7 @@ const SelectFileDialogAsideView = ({ passedId, headerName, isAvailableFolderList, + buttonName, }) => { const [isLoadingData, setIsLoadingData] = useState(false); const onSetLoadingData = (loading) => { @@ -71,9 +72,9 @@ const SelectFileDialogAsideView = ({
{header}
- + {/* {t("Translations:SelectFolder")} - + */}
diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js index 70269ca1fbe..dd9ba0a7e9f 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js @@ -176,6 +176,7 @@ class SelectFileDialogModalView extends React.Component { selectedFile, onClickSave, headerName, + buttonName, } = this.props; const { isLoading, isAvailable } = this.state; @@ -250,7 +251,7 @@ class SelectFileDialogModalView extends React.Component { className="select-file-modal-dialog-buttons-save" primary size="medium" - label={t("Common:SaveButton")} + label={buttonName ? buttonName : t("Common:SaveButton")} onClick={onClickSave} isDisabled={selectedFile.length === 0} /> diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js index 7eb3152ab5f..e477fa37ee1 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js @@ -238,6 +238,7 @@ class SelectFileDialogBody extends React.Component { onSetFileName, tReady, headerName, + buttonName, } = this.props; const { isVisible, @@ -286,6 +287,7 @@ class SelectFileDialogBody extends React.Component { passedId={passedId} header={header} isAvailableFolderList={isAvailableFolderList} + buttonName={buttonName} /> ) : ( ); } From 6a319d9bf81107c61021b43fb87268e6b2ef3ae2 Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 15:33:43 +0300 Subject: [PATCH 012/395] Web: Files: Fixed styles according the layouts. --- .../panels/SelectFileDialog/FilesListBody.js | 2 +- .../panels/SelectFileDialog/FilesListRow.js | 7 ++- .../panels/SelectFileDialog/ModalView.js | 2 +- .../StyledSelectFolderInput.js | 4 +- .../src/components/panels/StyledPanels.js | 45 ++++++++++++------- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/FilesListBody.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/FilesListBody.js index 67bddb3f8e0..7ef2a6d75b5 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/FilesListBody.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/FilesListBody.js @@ -129,7 +129,7 @@ const FilesListBody = ({ {fileName} + + {fileExst} + - -
- {fileExst} -
{children}
diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js index dd9ba0a7e9f..d47f71019e0 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/ModalView.js @@ -190,7 +190,7 @@ class SelectFileDialogModalView extends React.Component { zIndex={zIndex} onClose={onClose} className="select-file-modal-dialog" - style={{ maxWidth: "890px" }} + style={{ maxWidth: "725px" }} displayType="modal" bodyPadding="0" > diff --git a/products/ASC.Files/Client/src/components/panels/SelectFolderInput/StyledSelectFolderInput.js b/products/ASC.Files/Client/src/components/panels/SelectFolderInput/StyledSelectFolderInput.js index e380dd9868f..1892424874e 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFolderInput/StyledSelectFolderInput.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFolderInput/StyledSelectFolderInput.js @@ -2,8 +2,8 @@ import styled from "styled-components"; const StyledComponent = styled.div` .input-with-folder-path { - margin: 16px 0; - + margin-bottom: 16px; + margin-top: 3px; width: 100%; max-width: 820px; } diff --git a/products/ASC.Files/Client/src/components/panels/StyledPanels.js b/products/ASC.Files/Client/src/components/panels/StyledPanels.js index 29644ebd824..64425bae3ea 100644 --- a/products/ASC.Files/Client/src/components/panels/StyledPanels.js +++ b/products/ASC.Files/Client/src/components/panels/StyledPanels.js @@ -684,11 +684,17 @@ const StyledSelectFilePanel = styled.div` .select-file-dialog_aside-children { ${(props) => props.isHeaderChildren && `padding-bottom: 16px;`} } - .select-file-dialog_aside_body { - margin-top: 16px; + .select-file-dialog_aside_body, + .select-file-dialog_aside_body_files-list { + //margin-top: 16px; height: 100%; width: 290px; } + .select-file-dialog_aside_body_files-list { + margin-left: -17px; + padding-left: 16px; + ${(props) => props.isChecked && `background: #f8f9f9;`} + } .file-name { border-bottom: 1px solid #eceef1; @@ -723,9 +729,9 @@ const StyledSelectFilePanel = styled.div` .modal-dialog_body { display: grid; - grid-template-columns: 240px 1fr; + grid-template-columns: 212px 489px; height: 300px; - grid-column-gap: 8px; + // grid-column-gap: 8px; grid-template-areas: "children children" "tree files-list"; .modal-dialog_tree-body { ${(props) => @@ -764,30 +770,34 @@ const StyledFilesList = styled.div` margin-right: 8px; } .entry-title { - white-space: nowrap; - text-overflow: ellipsis; + font-weight: 600; + max-width: 100%; overflow: hidden; - max-width: ${(props) => - props.displayType === "aside" ? "240px" : "250px"}; + text-overflow: ellipsis; } + .files-list_file-owner { //margin-left: auto; - max-width: 207px; + max-width: 213px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: #a3a9ae; } - .entry-title { - font-weight: 600; - } + .file-exst { color: #a3a9ae; } .modal-dialog_file-name:hover { - background-color: #eceef1; + background-color: #f8f9f9; } .files-list_full-name { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + max-width: ${(props) => + props.displayType === "aside" ? "213px" : "274px"}; + grid-area: full-name; display: flex; ${(props) => @@ -801,11 +811,11 @@ const StyledFilesList = styled.div` } .select-file-dialog_checked { grid-area: checked-button; - padding-left: 6px; + //padding-left: 6px; } .files-list_file-children_wrapper { grid-area: owner-name; - margin-right: 16px; + margin-right: 12px; ${(props) => props.displayType === "aside" && css` @@ -814,7 +824,7 @@ const StyledFilesList = styled.div` } .modal-dialog_file-name { border-radius: 3px; - ${(props) => props.isChecked && `background:#eceef1;`} + ${(props) => props.isChecked && `background:#F8F9F9;`} cursor: ${(props) => (props.needRowSelection ? "pointer" : "default")}; border-bottom: 1px solid #eceef1; align-items: center; @@ -826,10 +836,11 @@ const StyledFilesList = styled.div` grid-template-areas: "checked-button icon-name full-name full-name" "checked-button icon-name owner-name owner-name"; ` : css` - height: 36px; + height: 41px; grid-template-areas: "checked-button icon-name full-name owner-name"; `} grid-template-columns: 22px 32px 1fr; + padding-left: 12px; } `; From e5d045c090c73a5aba4281eea78a5765dbac25fa Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 15:46:35 +0300 Subject: [PATCH 013/395] Web: Files: Added select file dialog to the main menu. --- .../components/Article/MainButton/index.js | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/products/ASC.Files/Client/src/components/Article/MainButton/index.js b/products/ASC.Files/Client/src/components/Article/MainButton/index.js index bec1807875a..50cb0fe2987 100644 --- a/products/ASC.Files/Client/src/components/Article/MainButton/index.js +++ b/products/ASC.Files/Client/src/components/Article/MainButton/index.js @@ -24,8 +24,9 @@ class ArticleMainButtonContent extends React.Component { }); }; - onSelectFile = () => { - console.log("Select from form"); + onShowSelectFileDialog = () => { + const { setSelectFileDialogVisible } = this.props; + setSelectFileDialogVisible(true); }; onUploadFileClick = () => { @@ -116,7 +117,7 @@ class ArticleMainButtonContent extends React.Component { className="main-button_drop-down" icon="images/form.file.react.svg" label={t("NewFormFile")} - onClick={this.onSelectFile} + onClick={this.onShowSelectFileDialog} /> { - const { firstLoad, fileActionStore, filter, canCreate } = filesStore; - const { isPrivacyFolder } = treeFoldersStore; - const { startUpload } = uploadDataStore; - - return { - homepage: config.homepage, - firstLoad, - isPrivacy: isPrivacyFolder, - filter, - canCreate, +export default inject( + ({ filesStore, uploadDataStore, treeFoldersStore, dialogsStore }) => { + const { firstLoad, fileActionStore, filter, canCreate } = filesStore; + const { isPrivacyFolder } = treeFoldersStore; + const { startUpload } = uploadDataStore; + const { setSelectFileDialogVisible } = dialogsStore; + return { + homepage: config.homepage, + firstLoad, + isPrivacy: isPrivacyFolder, + filter, + canCreate, - setAction: fileActionStore.setAction, - startUpload, - }; -})( + setAction: fileActionStore.setAction, + startUpload, + setSelectFileDialogVisible, + }; + } +)( withRouter( withTranslation(["Article", "Common"])( withLoader(observer(ArticleMainButtonContent))() From 79cf36a41c729b6b7760f1672483ec715eda4478 Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 16:28:31 +0300 Subject: [PATCH 014/395] Web: Files: Fixed tree opening. --- .../Client/src/components/panels/SelectFileDialog/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js index e477fa37ee1..ee1f609278c 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/index.js @@ -149,7 +149,7 @@ class SelectFileDialogBody extends React.Component { if (id) { setFolderId(id); - setExpandedPanelKeys([`${id}`]); + // setExpandedPanelKeys([`${id}`]); this.setState({ selectedFolder: id, hasNextPage: true, From 1a282c207374c85d0848ec4bdd17d81264a108f1 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 16:35:22 +0300 Subject: [PATCH 015/395] Config: Extra comma removed --- config/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/appsettings.json b/config/appsettings.json index 16b40522055..a75d5622376 100644 --- a/config/appsettings.json +++ b/config/appsettings.json @@ -61,7 +61,7 @@ "convert-docs": [ ".pptm", ".ppt", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".rtf" ], "edited-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".csv", ".docx", ".docxf", ".oform", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".txt", ".rtf", ".mht", ".html", ".htm" ], "encrypted-docs": [ ".docx", ".docxf", ".xlsx", ".pptx" ], - "formfilling-docs": [ ".oform", ], + "formfilling-docs": [ ".oform" ], "customfilter-docs": [ ".xlsx" ], "reviewed-docs": [ ".docx", ".docxf" ], "viewed-docs": [ ".pptx", ".pptm", ".ppt", ".ppsx", ".ppsm", ".pps", ".potx", ".potm", ".pot", ".odp", ".fodp", ".otp", ".gslides", ".xlsx", ".xlsm", ".xls", ".xltx", ".xltm", ".xlt", ".ods", ".fods", ".ots", ".gsheet", ".csv", ".docx", ".docxf", ".oform", ".docm", ".doc", ".dotx", ".dotm", ".dot", ".odt", ".fodt", ".ott", ".gdoc", ".txt", ".rtf", ".mht", ".html", ".htm", ".epub", ".pdf", ".djvu", ".xps" ], From 9e4b29a136b0a365df2b82e19344b20f0990a8e7 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 16:36:50 +0300 Subject: [PATCH 016/395] Web: Common: Api: Added new data parameters --- packages/asc-web-common/api/files/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/asc-web-common/api/files/index.js b/packages/asc-web-common/api/files/index.js index 1cbe89cd14c..545152c1e10 100644 --- a/packages/asc-web-common/api/files/index.js +++ b/packages/asc-web-common/api/files/index.js @@ -271,8 +271,8 @@ export function deleteFolder(folderId, deleteAfter, immediately) { return request(options); } -export function createFile(folderId, title) { - const data = { title }; +export function createFile(folderId, title, templateId) { + const data = { title, templateId }; const options = { method: "post", url: `/files/${folderId}/file`, From 2f7b465cea928b419848a8192231cc7d605b1d6f Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 16:37:46 +0300 Subject: [PATCH 017/395] Web: Files: Home: Added translation key for new form file --- products/ASC.Files/Client/public/locales/en/Home.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/products/ASC.Files/Client/public/locales/en/Home.json b/products/ASC.Files/Client/public/locales/en/Home.json index dc952d67b44..2867dff05b0 100644 --- a/products/ASC.Files/Client/public/locales/en/Home.json +++ b/products/ASC.Files/Client/public/locales/en/Home.json @@ -81,5 +81,6 @@ "UnblockVersion": "Unblock/Check-in", "UploadToFolder": "Upload to folder", "ViewList": "List", - "ViewTiles": "Tiles" + "ViewTiles": "Tiles", + "NewMasterForm": "New master form" } From 166cca86c6e81dc3ccf7c0665a1515632a0dc25d Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 16:38:26 +0300 Subject: [PATCH 018/395] Web: Files: Helpers: Added title for new forms --- products/ASC.Files/Client/src/helpers/utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/products/ASC.Files/Client/src/helpers/utils.js b/products/ASC.Files/Client/src/helpers/utils.js index 7ecc3c982a1..745f900575a 100644 --- a/products/ASC.Files/Client/src/helpers/utils.js +++ b/products/ASC.Files/Client/src/helpers/utils.js @@ -36,6 +36,8 @@ export const getDefaultFileName = (format) => { return i18n.t("NewSpreadsheet"); case "pptx": return i18n.t("NewPresentation"); + case "docxf": + return i18n.t("NewMasterForm"); default: return i18n.t("NewFolder"); } From 635dc7c7aa3037f6daf66e6502f7c0c91578f8a6 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 16:39:10 +0300 Subject: [PATCH 019/395] Web: Files: Store: Added new formats inside constants --- .../Client/src/store/DocserviceStore.js | 211 ++++++++++-------- 1 file changed, 119 insertions(+), 92 deletions(-) diff --git a/products/ASC.Files/Client/src/store/DocserviceStore.js b/products/ASC.Files/Client/src/store/DocserviceStore.js index 42f97fedb1a..c4d32532c5f 100644 --- a/products/ASC.Files/Client/src/store/DocserviceStore.js +++ b/products/ASC.Files/Client/src/store/DocserviceStore.js @@ -2,122 +2,135 @@ import { makeObservable } from "mobx"; import { presentInArray } from "../helpers/files-helpers"; class DocserviceStore { - coauthorDocs = [".pptx", ".ppsx", ".xlsx", ".csv", ".docx", ".txt"]; - commentedDocs = [".docx", ".xlsx", ".pptx"]; + coauthorDocs = [ + ".csv", + ".docx", + ".docxf", + ".oform", + ".ppsx", + ".pptx", + ".txt", + ".xlsx", + ]; + commentedDocs = [".docx", ".docxf", ".xlsx", ".pptx"]; convertDocs = [ - ".pptm", - ".ppt", - ".ppsm", - ".pps", - ".potx", - ".potm", - ".pot", - ".odp", - ".fodp", - ".otp", - ".xlsm", - ".xls", - ".xltx", - ".xltm", - ".xlt", - ".ods", - ".fods", - ".ots", - ".docm", ".doc", - ".dotx", - ".dotm", + ".docm", ".dot", - ".odt", + ".dotm", + ".dotx", + ".fodp", + ".fods", ".fodt", - ".ott", - ".rtf", - ]; - editedDocs = [ - ".pptx", - ".pptm", - ".ppt", - ".ppsx", - ".ppsm", - ".pps", - ".potx", - ".potm", - ".pot", ".odp", - ".fodp", + ".ods", + ".odt", ".otp", - ".xlsx", - ".xlsm", + ".ots", + ".ott", + ".pot", + ".potm", + ".potx", + ".pps", + ".ppsm", + ".ppt", + ".pptm", + ".rtf", ".xls", - ".xltx", - ".xltm", + ".xlsm", ".xlt", - ".ods", - ".fods", - ".ots", + ".xltm", + ".xltx", + ]; + editedDocs = [ ".csv", - ".docx", - ".docm", ".doc", - ".dotx", - ".dotm", + ".docm", + ".docx", + ".docxf", ".dot", - ".odt", + ".dotm", + ".dotx", + ".fodp", + ".fods", ".fodt", - ".ott", - ".txt", - ".rtf", - ".mht", - ".html", ".htm", - ]; - encryptedDocs = [".docx", ".xlsx", ".pptx"]; - formfillingDocs = [".docx"]; - customfilterDocs = [".xlsx"]; - reviewedDocs = [".docx"]; - viewedDocs = [ - ".pptx", - ".pptm", - ".ppt", - ".ppsx", - ".ppsm", - ".pps", - ".potx", - ".potm", - ".pot", + ".html", + ".mht", ".odp", - ".fodp", + ".ods", + ".odt", + ".oform", ".otp", - ".gslides", - ".xlsx", - ".xlsm", + ".ots", + ".ott", + ".pot", + ".potm", + ".potx", + ".pps", + ".ppsm", + ".ppsx", + ".ppt", + ".pptm", + ".pptx", + ".rtf", + ".txt", ".xls", - ".xltx", - ".xltm", + ".xlsm", + ".xlsx", ".xlt", - ".ods", - ".fods", - ".ots", - ".gsheet", + ".xltm", + ".xltx", + ]; + encryptedDocs = [".docx", ".docxf", ".xlsx", ".pptx"]; + formfillingDocs = [".oform"]; + customfilterDocs = [".xlsx"]; + reviewedDocs = [".docx", ".docxf"]; + viewedDocs = [ ".csv", - ".docx", - ".docm", + ".djvu", ".doc", - ".dotx", - ".dotm", + ".docm", + ".docx", + ".docxf", ".dot", - ".odt", + ".dotm", + ".dotx", + ".epub", + ".fodp", + ".fods", ".fodt", - ".ott", ".gdoc", - ".txt", - ".rtf", - ".mht", - ".html", + ".gsheet", + ".gslides", ".htm", - ".epub", + ".html", + ".mht", + ".odp", + ".ods", + ".odt", + ".oform", + ".otp", + ".ots", + ".ott", ".pdf", - ".djvu", + ".pot", + ".potm", + ".potx", + ".pps", + ".ppsm", + ".ppsx", + ".ppt", + ".pptm", + ".pptx", + ".rtf", + ".txt", + ".xls", + ".xlsm", + ".xlsx", + ".xlt", + ".xltm", + ".xltx", ".xps", ]; @@ -163,6 +176,20 @@ class DocserviceStore { { ".xltm": [".csv", ".ods", ".pdf", ".xlsx"] }, { ".xltx": [".csv", ".ods", ".pdf", ".xlsx"] }, { ".xps": [".pdf"] }, + { + ".docxf": [ + ".docx", + ".dotx", + ".epub", + ".fb2", + ".html", + ".odt", + ".ott", + ".pdf", + ".rtf", + ".txt", + ], + }, ]; constructor() { From e1a248ae7cd3866941292c836dc489c473935306 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 16:39:38 +0300 Subject: [PATCH 020/395] Web: Files: Store: Added new data parameters --- products/ASC.Files/Client/src/store/FilesStore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/products/ASC.Files/Client/src/store/FilesStore.js b/products/ASC.Files/Client/src/store/FilesStore.js index c860e297087..dde8a77d5aa 100644 --- a/products/ASC.Files/Client/src/store/FilesStore.js +++ b/products/ASC.Files/Client/src/store/FilesStore.js @@ -887,8 +887,8 @@ class FilesStore { return api.files.addFileToRecentlyViewed(fileId); }; - createFile = (folderId, title) => { - return api.files.createFile(folderId, title).then((file) => { + createFile = (folderId, title, templateId) => { + return api.files.createFile(folderId, title, templateId).then((file) => { return Promise.resolve(file); }); }; From cc4d8353350948d1bfea1840ab9a59aba75d0dd0 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 17 Nov 2021 16:43:29 +0300 Subject: [PATCH 021/395] Updated forms --- products/ASC.Files/Server/DocStore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/products/ASC.Files/Server/DocStore b/products/ASC.Files/Server/DocStore index b1063eae56d..9fea7818de9 160000 --- a/products/ASC.Files/Server/DocStore +++ b/products/ASC.Files/Server/DocStore @@ -1 +1 @@ -Subproject commit b1063eae56d183b5c0b6eb887115c378f3941ebe +Subproject commit 9fea7818de9abb29295c51b39a54c566bead9895 From 8546bc2662f3bd2abd6c9a3e90a38b693bb632b0 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 17:15:28 +0300 Subject: [PATCH 022/395] Web: Files: Home: Fixed translate file --- products/ASC.Files/Client/public/locales/en/Home.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/products/ASC.Files/Client/public/locales/en/Home.json b/products/ASC.Files/Client/public/locales/en/Home.json index 99aca3bb128..3b12768fc21 100644 --- a/products/ASC.Files/Client/public/locales/en/Home.json +++ b/products/ASC.Files/Client/public/locales/en/Home.json @@ -81,8 +81,8 @@ "UnblockVersion": "Unblock/Check-in", "UploadToFolder": "Upload to folder", "ViewList": "List", - "ViewTiles": "Tiles" - "NewMasterForm": "New master form" + "ViewTiles": "Tiles", + "NewMasterForm": "New master form", "ViewTiles": "Tiles", "Create": "Create" } From 7560d4aae58248627ae94e44e2286a143edae1a6 Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Wed, 17 Nov 2021 17:39:56 +0300 Subject: [PATCH 023/395] Web: Files: Added new form from file. --- products/ASC.Files/Client/src/store/DialogsStore.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/products/ASC.Files/Client/src/store/DialogsStore.js b/products/ASC.Files/Client/src/store/DialogsStore.js index e12689b4d34..6018268b7d3 100644 --- a/products/ASC.Files/Client/src/store/DialogsStore.js +++ b/products/ASC.Files/Client/src/store/DialogsStore.js @@ -177,7 +177,12 @@ class DialogsStore { }; createMasterForm = async (fileInfo) => { - console.log("fileInfo", fileInfo); + const { createFile, fetchFiles, filter } = this.filesStore; + const { id } = this.selectedFolderStore; + + createFile(id, `${fileInfo.title}.docxf`, fileInfo.id) + .then(() => fetchFiles(id, filter, true, true)) + .catch((err) => console.error(err)); }; } From 017b9e912cca06f7bc48c5af621323a59c8ed75d Mon Sep 17 00:00:00 2001 From: Viktor Fomin Date: Wed, 17 Nov 2021 17:41:46 +0300 Subject: [PATCH 024/395] Web: Files: add menu in trash --- .../src/pages/Home/Section/Header/index.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js b/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js index b7e3ff21c19..a2bdc075603 100644 --- a/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js +++ b/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js @@ -242,6 +242,7 @@ class SectionHeaderContent extends React.Component { }; onEmptyTrashAction = () => this.props.setEmptyTrashDialogVisible(true); + onRestoreAllAction = () => console.log("Restore all"); getContextOptionsFolder = () => { const { t } = this.props; @@ -292,6 +293,26 @@ class SectionHeaderContent extends React.Component { ]; }; + getContextOptionsTrash = () => { + const { t } = this.props; + return [ + { + key: "clear-trash", + label: t("EmptyRecycleBin"), + icon: "images/clear.active.react.svg", + onClick: this.onEmptyTrashAction, + disabled: false, + }, + { + key: "restore-all", + label: t("Translations:Restore"), + icon: "images/move.react.svg", + onClick: this.onRestoreAllAction, + disabled: false, + }, + ]; + }; + onBackToParentFolder = () => { const { setIsLoading, parentId, filter, fetchFiles } = this.props; setIsLoading(true); @@ -352,6 +373,7 @@ class SectionHeaderContent extends React.Component { isTabletView, personal, viewAs, + isRecycleBinFolder, } = this.props; const menuItems = this.getMenuItems(); @@ -449,6 +471,19 @@ class SectionHeaderContent extends React.Component { /> ) )} + {isRecycleBinFolder && ( + + )} )} @@ -468,6 +503,7 @@ export default inject( selectedFolderStore, filesActionsStore, settingsStore, + treeFoldersStore, }) => { const { setSelected, @@ -490,8 +526,10 @@ export default inject( setMoveToPanelVisible, setCopyPanelVisible, setDeleteDialogVisible, + setEmptyTrashDialogVisible, } = dialogsStore; + const { isRecycleBinFolder } = treeFoldersStore; const { deleteAction, downloadAction, getHeaderMenu } = filesActionsStore; return { @@ -524,6 +562,9 @@ export default inject( downloadAction, getHeaderMenu, getCheckboxItemLabel, + + isRecycleBinFolder, + setEmptyTrashDialogVisible, }; } )( From 4894779a1786018ce997145a8875b46084dcb390 Mon Sep 17 00:00:00 2001 From: Viktor Fomin Date: Wed, 17 Nov 2021 17:42:59 +0300 Subject: [PATCH 025/395] Web: Files: add restore all --- .../Client/src/pages/Home/Section/Header/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js b/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js index a2bdc075603..38945c2e283 100644 --- a/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js +++ b/products/ASC.Files/Client/src/pages/Home/Section/Header/index.js @@ -242,7 +242,10 @@ class SectionHeaderContent extends React.Component { }; onEmptyTrashAction = () => this.props.setEmptyTrashDialogVisible(true); - onRestoreAllAction = () => console.log("Restore all"); + onRestoreAllAction = () => { + this.props.setSelected("all"); + this.props.setMoveToPanelVisible(true); + }; getContextOptionsFolder = () => { const { t } = this.props; @@ -374,6 +377,7 @@ class SectionHeaderContent extends React.Component { personal, viewAs, isRecycleBinFolder, + isEmptyFilesList, } = this.props; const menuItems = this.getMenuItems(); @@ -471,7 +475,7 @@ class SectionHeaderContent extends React.Component { /> ) )} - {isRecycleBinFolder && ( + {isRecycleBinFolder && !isEmptyFilesList && ( Date: Wed, 17 Nov 2021 17:43:27 +0300 Subject: [PATCH 026/395] Web: Files: delete action --- products/ASC.Files/Client/src/store/FilesActionsStore.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/products/ASC.Files/Client/src/store/FilesActionsStore.js b/products/ASC.Files/Client/src/store/FilesActionsStore.js index da21f310cba..78a99d491eb 100644 --- a/products/ASC.Files/Client/src/store/FilesActionsStore.js +++ b/products/ASC.Files/Client/src/store/FilesActionsStore.js @@ -843,11 +843,7 @@ class FilesActionStore { label: t("Translations:Restore"), onClick: () => setMoveToPanelVisible(true), }) - .set("delete", deleteOption) - .set("emptyRecycleBin", { - label: t("EmptyRecycleBin"), - onClick: () => setEmptyTrashDialogVisible(true), - }); + .set("delete", deleteOption); return this.convertToArray(itemsCollection); }; getHeaderMenu = (t) => { From fb903bd9bfb1abe14fedfe3fff4d330463252a52 Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 18:11:18 +0300 Subject: [PATCH 027/395] Web: Files: Store: Added new formats inside document constant --- products/ASC.Files/Client/src/store/IconFormatsStore.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/products/ASC.Files/Client/src/store/IconFormatsStore.js b/products/ASC.Files/Client/src/store/IconFormatsStore.js index 6cfbdde1ae4..b6e516a192f 100644 --- a/products/ASC.Files/Client/src/store/IconFormatsStore.js +++ b/products/ASC.Files/Client/src/store/IconFormatsStore.js @@ -118,6 +118,8 @@ class IconFormatsStore { ".doct", ".docy", ".gdoc", + ".docxf", + ".oform", ]; presentation = [ ".pps", From e6f008cc6f5cb109f3e988a75867cfd6fae3feec Mon Sep 17 00:00:00 2001 From: Ilya Oleshko Date: Wed, 17 Nov 2021 18:16:23 +0300 Subject: [PATCH 028/395] Web: Files: Store: Added convert map docx to docxf --- products/ASC.Files/Client/src/store/DocserviceStore.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/products/ASC.Files/Client/src/store/DocserviceStore.js b/products/ASC.Files/Client/src/store/DocserviceStore.js index c4d32532c5f..4f6f75e293c 100644 --- a/products/ASC.Files/Client/src/store/DocserviceStore.js +++ b/products/ASC.Files/Client/src/store/DocserviceStore.js @@ -139,7 +139,7 @@ class DocserviceStore { { ".doc": [".docx", ".odt", ".pdf", ".rtf", ".txt"] }, { ".docm": [".docx", ".odt", ".pdf", ".rtf", ".txt"] }, { ".doct": [".docx"] }, - { ".docx": [".odt", ".pdf", ".rtf", ".txt"] }, + { ".docx": [".docxf", ".odt", ".pdf", ".rtf", ".txt"] }, { ".dot": [".docx", ".odt", ".pdf", ".rtf", ".txt"] }, { ".dotm": [".docx", ".odt", ".pdf", ".rtf", ".txt"] }, { ".dotx": [".docx", ".odt", ".pdf", ".rtf", ".txt"] }, From 68d889fb2b176fa8b6daefb327ba486720bc965e Mon Sep 17 00:00:00 2001 From: Tatiana Lopaeva Date: Thu, 18 Nov 2021 09:06:03 +0300 Subject: [PATCH 029/395] Web: Fixed can create in editor dialog, changed translation, added buttons of selection folder for files dialog. --- .../public/locales/en/SelectFolder.json | 3 +- .../panels/SelectFileDialog/AsideView.js | 2 + .../panels/SelectFolderDialog/AsideView.js | 5 +- .../panels/SelectFolderDialog/ModalView.js | 5 +- .../panels/SelectFolderDialog/index.js | 63 ++++++++++++++----- .../panels/SelectFolderInput/index.js | 2 + 6 files changed, 59 insertions(+), 21 deletions(-) diff --git a/products/ASC.Files/Client/public/locales/en/SelectFolder.json b/products/ASC.Files/Client/public/locales/en/SelectFolder.json index fd719cf5464..000bafc0077 100644 --- a/products/ASC.Files/Client/public/locales/en/SelectFolder.json +++ b/products/ASC.Files/Client/public/locales/en/SelectFolder.json @@ -1,3 +1,4 @@ { - "NotAvailableFolder": "No folders available" + "NotAvailableFolder": "No folders available", + "Select": "Select" } diff --git a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js index 0f393854656..1053630c1ad 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFileDialog/AsideView.js @@ -92,6 +92,8 @@ const SelectFileDialogAsideView = ({ fileName={fileName} displayType={displayType} dialogWithFiles + showButtons + selectionButtonPrimary /> {selectedFolder && !isLoadingData ? ( diff --git a/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/AsideView.js b/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/AsideView.js index a0625fd9d55..2b3695c30a2 100644 --- a/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/AsideView.js +++ b/products/ASC.Files/Client/src/components/panels/SelectFolderDialog/AsideView.js @@ -28,6 +28,7 @@ const SelectFolderDialogAsideView = ({ header, canCreate, isLoading, + primaryButtonName, }) => { return ( @@ -87,13 +88,13 @@ const SelectFolderDialogAsideView = ({ className="select-folder-dialog-buttons-save" primary size="big" - label={t("Common:SaveButton")} + label={primaryButtonName} onClick={onSave} isDisabled={isLoadingData || !isAvailable || !canCreate} />