Merge branch 'release/rc-v1.2.0' of https://github.com/ONLYOFFICE/DocSpace into release/rc-v1.2.0
This commit is contained in:
commit
7bc819dba7
@ -95,7 +95,7 @@
|
||||
"chunk-size": 10485760,
|
||||
"url": "/"
|
||||
},
|
||||
"viewed-images": [ ".bmp", ".gif", ".jpeg", ".jpg", ".png", ".ico", ".tif", ".tiff", ".webp" ],
|
||||
"viewed-images": [ ".svg", ".bmp", ".gif", ".jpeg", ".jpg", ".png", ".ico", ".tif", ".tiff", ".webp" ],
|
||||
"viewed-media": [ ".aac", ".flac", ".m4a", ".mp3", ".oga", ".ogg", ".wav", ".f4v", ".m4v", ".mov", ".mp4", ".ogv", ".webm" ],
|
||||
"index": [ ".pptx", ".xlsx", ".docx" ],
|
||||
"oform": {
|
||||
|
@ -46,6 +46,7 @@
|
||||
"FolderRenamed": "The folder '{{folderTitle}}' is renamed to '{{newFoldedTitle}}'",
|
||||
"Forms": "Forms",
|
||||
"FormsTemplates": "Forms templates",
|
||||
"GoToMyRooms": "Go to My rooms",
|
||||
"GoToPersonal": "Go to Personal",
|
||||
"GoToShared": "Go to Shared",
|
||||
"Images": "Images",
|
||||
@ -68,6 +69,8 @@
|
||||
"NewPresentation": "New presentation",
|
||||
"NewRoom": "New room",
|
||||
"NewSpreadsheet": "New spreadsheet",
|
||||
"NoAccessRoomTitle": "Sorry, you don't have access to this room",
|
||||
"NoAccessRoomDescription": "You will be redirected to the My Rooms automatically in 5 seconds.",
|
||||
"NoFilesHereYet": "No files here yet",
|
||||
"Open": "Open",
|
||||
"OpenLocation": "Open location",
|
||||
|
@ -29,7 +29,7 @@ export default function withBadges(WrappedComponent) {
|
||||
isTrashFolder,
|
||||
} = this.props;
|
||||
if (isTrashFolder) return;
|
||||
fetchFileVersions(item.id + "", item.access);
|
||||
fetchFileVersions(item.id + "", item.security);
|
||||
setIsVerHistoryPanel(true);
|
||||
};
|
||||
|
||||
@ -82,16 +82,13 @@ export default function withBadges(WrappedComponent) {
|
||||
t,
|
||||
theme,
|
||||
item,
|
||||
canWebEdit,
|
||||
isTrashFolder,
|
||||
isPrivacyFolder,
|
||||
canConvert,
|
||||
onFilesClick,
|
||||
isAdmin,
|
||||
isDesktopClient,
|
||||
sectionWidth,
|
||||
viewAs,
|
||||
canViewVersionFileHistory,
|
||||
} = this.props;
|
||||
const { fileStatus, access } = item;
|
||||
|
||||
@ -112,8 +109,6 @@ export default function withBadges(WrappedComponent) {
|
||||
showNew={showNew}
|
||||
newItems={newItems}
|
||||
sectionWidth={sectionWidth}
|
||||
canWebEdit={canWebEdit}
|
||||
canConvert={canConvert}
|
||||
isTrashFolder={isTrashFolder}
|
||||
isPrivacyFolder={isPrivacyFolder}
|
||||
isDesktopClient={isDesktopClient}
|
||||
@ -124,7 +119,6 @@ export default function withBadges(WrappedComponent) {
|
||||
setConvertDialogVisible={this.setConvertDialogVisible}
|
||||
onFilesClick={onFilesClick}
|
||||
viewAs={viewAs}
|
||||
canViewVersionFileHistory={canViewVersionFileHistory}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -143,8 +137,6 @@ export default function withBadges(WrappedComponent) {
|
||||
versionHistoryStore,
|
||||
dialogsStore,
|
||||
filesStore,
|
||||
settingsStore,
|
||||
accessRightsStore,
|
||||
},
|
||||
{ item }
|
||||
) => {
|
||||
@ -159,17 +151,10 @@ export default function withBadges(WrappedComponent) {
|
||||
} = dialogsStore;
|
||||
const { setIsLoading } = filesStore;
|
||||
|
||||
const canWebEdit = settingsStore.canWebEdit(item.fileExst);
|
||||
const canConvert = settingsStore.canConvert(item.fileExst);
|
||||
const canViewVersionFileHistory = accessRightsStore.canViewVersionFileHistory(
|
||||
item
|
||||
);
|
||||
|
||||
return {
|
||||
theme,
|
||||
isAdmin: auth.isAdmin,
|
||||
canWebEdit,
|
||||
canConvert,
|
||||
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
isPrivacyFolder,
|
||||
homepage: config.homepage,
|
||||
@ -183,7 +168,6 @@ export default function withBadges(WrappedComponent) {
|
||||
setConvertItem,
|
||||
isDesktopClient,
|
||||
setPinAction,
|
||||
canViewVersionFileHistory,
|
||||
};
|
||||
}
|
||||
)(observer(WithBadges));
|
||||
|
@ -201,7 +201,6 @@ export default function withFileActions(WrappedFileItem) {
|
||||
checked,
|
||||
dragging,
|
||||
isFolder,
|
||||
canWebEdit,
|
||||
} = this.props;
|
||||
const { fileExst, access, id } = item;
|
||||
|
||||
|
@ -10,7 +10,7 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
|
||||
this.state = {
|
||||
isLoading: false,
|
||||
isCanWebEdit: props.canWebEdit(props.item.fileExst),
|
||||
isCanWebEdit: props.item.viewAccessability?.WebEdit,
|
||||
};
|
||||
}
|
||||
|
||||
@ -50,15 +50,7 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
render() {
|
||||
const { isLoading, isCanWebEdit } = this.state;
|
||||
|
||||
const {
|
||||
t,
|
||||
theme,
|
||||
item,
|
||||
isAdmin,
|
||||
sectionWidth,
|
||||
viewAs,
|
||||
canLockFile,
|
||||
} = this.props;
|
||||
const { t, theme, item, isAdmin, sectionWidth, viewAs } = this.props;
|
||||
|
||||
const quickButtonsComponent = (
|
||||
<QuickButtons
|
||||
@ -72,7 +64,6 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
isCanWebEdit={isCanWebEdit}
|
||||
onClickLock={this.onClickLock}
|
||||
onClickFavorite={this.onClickFavorite}
|
||||
canLockFile={canLockFile}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -90,8 +81,7 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
auth,
|
||||
filesActionsStore,
|
||||
dialogsStore,
|
||||
settingsStore,
|
||||
accessRightsStore,
|
||||
|
||||
treeFoldersStore,
|
||||
}) => {
|
||||
const {
|
||||
@ -101,8 +91,6 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
} = filesActionsStore;
|
||||
const { isPersonalRoom } = treeFoldersStore;
|
||||
const { setSharingPanelVisible } = dialogsStore;
|
||||
const { canWebEdit } = settingsStore;
|
||||
const { canLockFile } = accessRightsStore;
|
||||
|
||||
return {
|
||||
theme: auth.settingsStore.theme,
|
||||
@ -111,8 +99,7 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
setFavoriteAction,
|
||||
onSelectItem,
|
||||
setSharingPanelVisible,
|
||||
canWebEdit,
|
||||
canLockFile,
|
||||
|
||||
isPersonalRoom,
|
||||
};
|
||||
}
|
||||
|
@ -58,11 +58,9 @@ const Badges = ({
|
||||
newItems,
|
||||
sectionWidth,
|
||||
item,
|
||||
canWebEdit,
|
||||
isTrashFolder,
|
||||
isPrivacyFolder,
|
||||
isDesktopClient,
|
||||
canConvert,
|
||||
accessToEdit,
|
||||
showNew,
|
||||
onFilesClick,
|
||||
@ -71,7 +69,6 @@ const Badges = ({
|
||||
setConvertDialogVisible,
|
||||
viewAs,
|
||||
onUnpinClick,
|
||||
canViewVersionFileHistory,
|
||||
}) => {
|
||||
const {
|
||||
id,
|
||||
@ -143,7 +140,7 @@ const Badges = ({
|
||||
"data-id": id,
|
||||
};
|
||||
|
||||
const onShowVersionHistoryProp = canViewVersionFileHistory
|
||||
const onShowVersionHistoryProp = item.security?.ReadHistory
|
||||
? { onClick: onShowVersionHistory }
|
||||
: {};
|
||||
|
||||
@ -161,7 +158,7 @@ const Badges = ({
|
||||
title={isForm ? t("Common:FillFormButton") : t("Common:EditButton")}
|
||||
/>
|
||||
)}
|
||||
{canConvert && !isTrashFolder && (
|
||||
{item.viewAccessability?.Convert && !isTrashFolder && (
|
||||
<ColorTheme
|
||||
themeId={ThemeType.IconButton}
|
||||
onClick={setConvertDialogVisible}
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
size,
|
||||
} from "@docspace/components/utils/device";
|
||||
import { isMobile, isMobileOnly } from "react-device-detect";
|
||||
import { classNames } from "@docspace/components/utils/classNames";
|
||||
|
||||
const EmptyPageStyles = css`
|
||||
padding: 44px 0px 64px 0px;
|
||||
@ -122,6 +123,10 @@ const EmptyFolderWrapper = styled.div`
|
||||
}
|
||||
`}
|
||||
}
|
||||
|
||||
.empty-folder_room-not-found {
|
||||
margin-top: 70px;
|
||||
}
|
||||
`;
|
||||
|
||||
const EmptyFoldersContainer = (props) => {
|
||||
@ -138,6 +143,7 @@ const EmptyFoldersContainer = (props) => {
|
||||
isEmptyPage,
|
||||
sectionWidth,
|
||||
isEmptyFolderContainer,
|
||||
className,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
@ -148,7 +154,7 @@ const EmptyFoldersContainer = (props) => {
|
||||
>
|
||||
<EmptyScreenContainer
|
||||
sectionWidth={sectionWidth}
|
||||
className="empty-folder_container"
|
||||
className={classNames("empty-folder_container", className)}
|
||||
style={style}
|
||||
imageStyle={imageStyle}
|
||||
imageSrc={imageSrc}
|
||||
|
@ -166,6 +166,7 @@ export default inject(
|
||||
access,
|
||||
id: folderId,
|
||||
roomType,
|
||||
security,
|
||||
} = selectedFolderStore;
|
||||
|
||||
let id;
|
||||
@ -176,11 +177,11 @@ export default inject(
|
||||
|
||||
const isRooms = !!roomType;
|
||||
|
||||
const { canCreateFiles, canInviteUserInRoom } = accessRightsStore;
|
||||
const { canCreateFiles } = accessRightsStore;
|
||||
|
||||
const { onClickInviteUsers } = contextOptionsStore;
|
||||
|
||||
const canInviteUsers = isRooms && canInviteUserInRoom({ access }); // skip sub-folders
|
||||
const canInviteUsers = isRooms && security?.EditAccess; // skip sub-folders
|
||||
|
||||
return {
|
||||
fetchFiles,
|
||||
|
@ -0,0 +1,105 @@
|
||||
import React from "react";
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import EmptyContainer from "./EmptyContainer";
|
||||
import Link from "@docspace/components/link";
|
||||
|
||||
import RoomsFilter from "@docspace/common/api/rooms/filter";
|
||||
import { combineUrl } from "@docspace/common/utils";
|
||||
import { getCategoryUrl } from "SRC_DIR/helpers/utils";
|
||||
import { AppServerConfig } from "@docspace/common/constants";
|
||||
import history from "@docspace/common/history";
|
||||
import config from "PACKAGE_FILE";
|
||||
|
||||
const RoomNoAccessContainer = (props) => {
|
||||
const {
|
||||
t,
|
||||
setIsLoading,
|
||||
linkStyles,
|
||||
fetchRooms,
|
||||
setAlreadyFetchingRooms,
|
||||
categoryType,
|
||||
isEmptyPage,
|
||||
sectionWidth,
|
||||
} = props;
|
||||
|
||||
const descriptionRoomNoAccess = t("NoAccessRoomDescription");
|
||||
const titleRoomNoAccess = t("NoAccessRoomTitle");
|
||||
|
||||
React.useEffect(() => {
|
||||
const timer = setTimeout(onGoToShared, 5000);
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
const onGoToShared = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
setAlreadyFetchingRooms(true);
|
||||
fetchRooms(null, null)
|
||||
.then(() => {
|
||||
const filter = RoomsFilter.getDefault();
|
||||
|
||||
const filterParamsStr = filter.toUrlParams();
|
||||
|
||||
const url = getCategoryUrl(categoryType, filter.folder);
|
||||
|
||||
const pathname = `${url}?${filterParamsStr}`;
|
||||
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, config.homepage, pathname)
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const goToButtons = (
|
||||
<div className="empty-folder_container-links">
|
||||
<img
|
||||
className="empty-folder_container-image"
|
||||
src="images/empty-folder-image.svg"
|
||||
onClick={onGoToShared}
|
||||
alt="folder_icon"
|
||||
/>
|
||||
<Link onClick={onGoToShared} {...linkStyles}>
|
||||
{t("GoToMyRooms")}
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
|
||||
const propsRoomNotFoundOrMoved = {
|
||||
headerText: titleRoomNoAccess,
|
||||
descriptionText: descriptionRoomNoAccess,
|
||||
imageSrc: "static/images/manage.access.rights.react.svg",
|
||||
buttons: goToButtons,
|
||||
};
|
||||
|
||||
return (
|
||||
<EmptyContainer
|
||||
isEmptyPage={isEmptyPage}
|
||||
sectionWidth={sectionWidth}
|
||||
imageStyle={{ marginRight: "20px" }}
|
||||
className="empty-folder_room-not-found"
|
||||
{...propsRoomNotFoundOrMoved}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ filesStore }) => {
|
||||
const {
|
||||
setIsLoading,
|
||||
fetchRooms,
|
||||
categoryType,
|
||||
setAlreadyFetchingRooms,
|
||||
isEmptyPage,
|
||||
} = filesStore;
|
||||
return {
|
||||
setIsLoading,
|
||||
fetchRooms,
|
||||
categoryType,
|
||||
setAlreadyFetchingRooms,
|
||||
isEmptyPage,
|
||||
};
|
||||
})(withTranslation(["Files"])(observer(RoomNoAccessContainer)));
|
@ -6,6 +6,7 @@ import EmptyFolderContainer from "./EmptyFolderContainer";
|
||||
import { FileAction } from "@docspace/common/constants";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { Events } from "@docspace/common/constants";
|
||||
import RoomNoAccessContainer from "./RoomNoAccessContainer";
|
||||
|
||||
const linkStyles = {
|
||||
isHovered: true,
|
||||
@ -21,6 +22,7 @@ const EmptyContainer = ({
|
||||
theme,
|
||||
setCreateRoomDialogVisible,
|
||||
sectionWidth,
|
||||
isRoomNotFoundOrMoved,
|
||||
}) => {
|
||||
linkStyles.color = theme.filesEmptyContainer.linkColor;
|
||||
|
||||
@ -43,6 +45,15 @@ const EmptyContainer = ({
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
if (isRoomNotFoundOrMoved) {
|
||||
return (
|
||||
<RoomNoAccessContainer
|
||||
linkStyles={linkStyles}
|
||||
sectionWidth={sectionWidth}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return isFiltered ? (
|
||||
<EmptyFilterContainer linkStyles={linkStyles} />
|
||||
) : parentId === 0 ? (
|
||||
@ -69,7 +80,7 @@ export default inject(
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
}) => {
|
||||
const { filter, roomsFilter } = filesStore;
|
||||
const { filter, roomsFilter, isErrorRoomNotAvailable } = filesStore;
|
||||
|
||||
const {
|
||||
authorType,
|
||||
@ -113,12 +124,18 @@ export default inject(
|
||||
searchInContent) &&
|
||||
!(isPrivacyFolder && isMobile);
|
||||
|
||||
const isRoomNotFoundOrMoved =
|
||||
isFiltered === null &&
|
||||
selectedFolderStore.parentId === null &&
|
||||
isErrorRoomNotAvailable;
|
||||
|
||||
return {
|
||||
theme: auth.settingsStore.theme,
|
||||
isFiltered,
|
||||
setCreateRoomDialogVisible,
|
||||
|
||||
parentId: selectedFolderStore.parentId,
|
||||
isRoomNotFoundOrMoved,
|
||||
};
|
||||
}
|
||||
)(observer(EmptyContainer));
|
||||
|
@ -139,8 +139,19 @@ const CreateEvent = ({
|
||||
})
|
||||
.then(() => editCompleteAction(item, type))
|
||||
.catch((err) => {
|
||||
if (err.indexOf("password") == -1) {
|
||||
toastr.error(err, t("Common:Warning"));
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
err?.response?.data?.error?.message ||
|
||||
err?.statusText ||
|
||||
err?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = err;
|
||||
}
|
||||
|
||||
if (errorMessage.indexOf("password") == -1) {
|
||||
toastr.error(errorMessage, t("Common:Warning"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,10 @@ const QuickButtons = (props) => {
|
||||
onClickFavorite,
|
||||
viewAs,
|
||||
isCanWebEdit,
|
||||
canLockFile,
|
||||
} = props;
|
||||
|
||||
const { id, locked, fileStatus, title, fileExst, access, folderType } = item;
|
||||
const canLockFileAbility = canLockFile(item);
|
||||
const { id, locked, fileStatus, title, fileExst, security } = item;
|
||||
const canLockFileAbility = security?.Lock;
|
||||
|
||||
const isFavorite =
|
||||
(fileStatus & FileStatus.IsFavorite) === FileStatus.IsFavorite;
|
||||
|
@ -92,8 +92,19 @@ const ConvertPasswordDialogComponent = (props) => {
|
||||
onClose();
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.indexOf("password") == -1) {
|
||||
toastr.error(err, t("Common:Warning"));
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
err?.response?.data?.error?.message ||
|
||||
err?.statusText ||
|
||||
err?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = err;
|
||||
}
|
||||
|
||||
if (errorMessage.indexOf("password") == -1) {
|
||||
toastr.error(errorMessage, t("Common:Warning"));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -118,8 +129,18 @@ const ConvertPasswordDialogComponent = (props) => {
|
||||
editCompleteAction(fileInfo);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.indexOf("password") == -1) {
|
||||
toastr.error(err, t("Common:Warning"));
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
err?.response?.data?.error?.message ||
|
||||
err?.statusText ||
|
||||
err?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = err;
|
||||
}
|
||||
if (errorMessage.indexOf("password") == -1) {
|
||||
toastr.error(errorMessage, t("Common:Warning"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -359,12 +359,7 @@ export default inject(
|
||||
name = splitted[0];
|
||||
}
|
||||
const { personal, theme } = auth.settingsStore;
|
||||
const {
|
||||
canViewedDocs,
|
||||
isMediaOrImage,
|
||||
getIconSrc,
|
||||
isArchive,
|
||||
} = settingsStore;
|
||||
const { getIconSrc, isArchive } = settingsStore;
|
||||
const {
|
||||
uploaded,
|
||||
primaryProgressDataStore,
|
||||
@ -382,7 +377,8 @@ export default inject(
|
||||
setCurrentItem,
|
||||
} = mediaViewerDataStore;
|
||||
const { loadingFile: file } = primaryProgressDataStore;
|
||||
const isMedia = isMediaOrImage(ext);
|
||||
const isMedia =
|
||||
item.viewAccessability?.ImageView || item.viewAccessability?.MediaView;
|
||||
const isMediaActive =
|
||||
playlist.findIndex((el) => el.fileId === item.fileId) !== -1;
|
||||
|
||||
@ -395,7 +391,8 @@ export default inject(
|
||||
? loadingFile.percent
|
||||
: null;
|
||||
|
||||
const downloadInCurrentTab = isArchive(ext) || !canViewedDocs(ext);
|
||||
const downloadInCurrentTab =
|
||||
isArchive(ext) || !item.viewAccessability?.WebView;
|
||||
|
||||
return {
|
||||
isPersonal: personal,
|
||||
|
@ -71,8 +71,18 @@ class ConfirmRoute extends React.Component {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, path, `/error=${error}`)
|
||||
combineUrl(AppServerConfig.proxyURL, path, `/error=${errorMessage}`)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -26,10 +26,24 @@ class ActivateEmail extends React.PureComponent {
|
||||
)
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
.catch((error) => {
|
||||
// console.log('activate email error', e);
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
tryRedirectTo(
|
||||
combineUrl(AppServerConfig.proxyURL, `/login/error?message=${e}`)
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
`/login/error?message=${errorMessage}`
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
|
@ -23,9 +23,22 @@ class ChangeEmail extends React.PureComponent {
|
||||
)
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
.catch((error) => {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
console.log("change client email error", e);
|
||||
tryRedirectTo(combineUrl(AppServerConfig.proxyURL, `/error=${e}`));
|
||||
tryRedirectTo(
|
||||
combineUrl(AppServerConfig.proxyURL, `/error=${errorMessage}`)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,18 @@ const ChangePasswordForm = (props) => {
|
||||
tryRedirectTo(defaultPage);
|
||||
})
|
||||
.catch((error) => {
|
||||
toastr.error(t(`${error}`));
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
toastr.error(t(`${errorMessage}`));
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
@ -339,8 +339,19 @@ const Confirm = (props) => {
|
||||
createConfirmUser(personalData, loginData, headerKey)
|
||||
.then(() => window.location.replace(defaultPage))
|
||||
.catch((error) => {
|
||||
console.error("confirm error", error);
|
||||
setEmailErrorText(error);
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
console.error("confirm error", errorMessage);
|
||||
setEmailErrorText(errorMessage);
|
||||
setEmailValid(false);
|
||||
setIsLoading(false);
|
||||
});
|
||||
|
@ -120,8 +120,18 @@ const TfaActivationForm = withLoader((props) => {
|
||||
const url = await loginWithCodeAndCookie(code, linkData.confirmHeader);
|
||||
history.push("/");
|
||||
}
|
||||
} catch (e) {
|
||||
setError(e);
|
||||
} catch (err) {
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
err?.response?.data?.error?.message ||
|
||||
err?.statusText ||
|
||||
err?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = err;
|
||||
}
|
||||
setError(errorMessage);
|
||||
toastr.error(e);
|
||||
}
|
||||
setIsLoading(false);
|
||||
|
@ -34,11 +34,22 @@ export default function withLoader(WrappedComponent) {
|
||||
axios
|
||||
.all([getSettings(), getPortalPasswordSettings(confirmHeader)])
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
console.error(errorMessage);
|
||||
history.push(
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
`/login/error?message=${error}`
|
||||
`/login/error?message=${errorMessage}`
|
||||
)
|
||||
);
|
||||
});
|
||||
@ -48,11 +59,21 @@ export default function withLoader(WrappedComponent) {
|
||||
useEffect(() => {
|
||||
if (type === "LinkInvite") {
|
||||
axios.all([getAuthProviders(), getCapabilities()]).catch((error) => {
|
||||
console.error(error);
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
console.error(errorMessage);
|
||||
history.push(
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
`/login/error?message=${error}`
|
||||
`/login/error?message=${errorMessage}`
|
||||
)
|
||||
);
|
||||
});
|
||||
|
@ -49,16 +49,12 @@ class MembersHelper {
|
||||
};
|
||||
};
|
||||
|
||||
getOptionsByRoomType = (
|
||||
roomType,
|
||||
canChangeUserRole = false,
|
||||
canDeleteUser = false
|
||||
) => {
|
||||
getOptionsByRoomType = (roomType, canChangeUserRole = false) => {
|
||||
if (!roomType) return;
|
||||
|
||||
const options = this.getOptions();
|
||||
|
||||
const deleteOption = canDeleteUser
|
||||
const deleteOption = canChangeUserRole
|
||||
? [
|
||||
{ key: "s2", isSeparator: true },
|
||||
{
|
||||
@ -69,50 +65,41 @@ class MembersHelper {
|
||||
]
|
||||
: [];
|
||||
|
||||
let availableOptions = [];
|
||||
|
||||
switch (roomType) {
|
||||
case RoomsType.FillingFormsRoom:
|
||||
if (canChangeUserRole)
|
||||
availableOptions = [
|
||||
options.roomAdmin,
|
||||
options.formFiller,
|
||||
options.viewer,
|
||||
];
|
||||
return [...availableOptions, ...deleteOption];
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.formFiller,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
];
|
||||
case RoomsType.EditingRoom:
|
||||
if (canChangeUserRole)
|
||||
availableOptions = [
|
||||
options.roomAdmin,
|
||||
options.editor,
|
||||
options.viewer,
|
||||
];
|
||||
return [...availableOptions, ...deleteOption];
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.editor,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
];
|
||||
case RoomsType.ReviewRoom:
|
||||
if (canChangeUserRole)
|
||||
availableOptions = [
|
||||
options.roomAdmin,
|
||||
options.reviewer,
|
||||
options.commentator,
|
||||
options.viewer,
|
||||
];
|
||||
return [...availableOptions, ...deleteOption];
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.reviewer,
|
||||
options.commentator,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
];
|
||||
case RoomsType.ReadOnlyRoom:
|
||||
if (canChangeUserRole)
|
||||
availableOptions = [options.roomAdmin, options.viewer];
|
||||
return [...availableOptions, ...deleteOption];
|
||||
return [options.roomAdmin, options.viewer, ...deleteOption];
|
||||
case RoomsType.CustomRoom:
|
||||
if (canChangeUserRole)
|
||||
availableOptions = [
|
||||
options.roomAdmin,
|
||||
options.editor,
|
||||
options.formFiller,
|
||||
options.reviewer,
|
||||
options.commentator,
|
||||
options.viewer,
|
||||
];
|
||||
|
||||
return [...availableOptions, ...deleteOption];
|
||||
return [
|
||||
options.roomAdmin,
|
||||
options.editor,
|
||||
options.formFiller,
|
||||
options.reviewer,
|
||||
options.commentator,
|
||||
options.viewer,
|
||||
...deleteOption,
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -123,7 +123,11 @@ const InfoPanelBodyContent = ({
|
||||
const newSelectionParentRoom = await getRoomInfo(currentFolderRoomId);
|
||||
if (storeRoomId === newSelectionParentRoom.id) return;
|
||||
|
||||
setSelectionParentRoom(normalizeSelection(newSelectionParentRoom));
|
||||
if (
|
||||
newSelectionParentRoom.parentId === newSelectionParentRoom.rootFolderId
|
||||
) {
|
||||
setSelectionParentRoom(null);
|
||||
} else setSelectionParentRoom(normalizeSelection(newSelectionParentRoom));
|
||||
}, [selectedFolder]);
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
@ -13,21 +13,17 @@ const CommentEditor = ({
|
||||
setSelection,
|
||||
fetchFileVersions,
|
||||
updateCommentVersion,
|
||||
canChangeVersionFileHistory,
|
||||
setVerHistoryFileId,
|
||||
setVerHistoryFileAccess,
|
||||
}) => {
|
||||
const { id, comment, version, access, folderType } = item;
|
||||
|
||||
const changeVersionHistoryAbility = canChangeVersionFileHistory({
|
||||
access,
|
||||
folderType,
|
||||
editing,
|
||||
});
|
||||
setVerHistoryFileId,
|
||||
setVerHistoryFileSecurity,
|
||||
}) => {
|
||||
const { id, comment, version, security } = item;
|
||||
|
||||
const changeVersionHistoryAbility = !editing && security?.EditHistory;
|
||||
|
||||
useEffect(() => {
|
||||
setVerHistoryFileId(id);
|
||||
setVerHistoryFileAccess(access);
|
||||
setVerHistoryFileSecurity(security);
|
||||
}, []);
|
||||
|
||||
const [isEdit, setIsEdit] = useState(false);
|
||||
@ -44,7 +40,7 @@ const CommentEditor = ({
|
||||
const onSave = async () => {
|
||||
setIsLoading(true);
|
||||
|
||||
await fetchFileVersions(id, access).catch((err) => {
|
||||
await fetchFileVersions(id, security).catch((err) => {
|
||||
toastr.error(err);
|
||||
setIsLoading(false);
|
||||
});
|
||||
@ -116,7 +112,7 @@ const CommentEditor = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth, versionHistoryStore, accessRightsStore }) => {
|
||||
export default inject(({ auth, versionHistoryStore }) => {
|
||||
const { setSelection } = auth.infoPanelStore;
|
||||
|
||||
const {
|
||||
@ -126,19 +122,18 @@ export default inject(({ auth, versionHistoryStore, accessRightsStore }) => {
|
||||
isEditing,
|
||||
fileId,
|
||||
setVerHistoryFileId,
|
||||
setVerHistoryFileAccess,
|
||||
setVerHistoryFileSecurity,
|
||||
} = versionHistoryStore;
|
||||
|
||||
const { canChangeVersionFileHistory } = accessRightsStore;
|
||||
const editing = isEditingVersion || isEditing;
|
||||
|
||||
return {
|
||||
setSelection,
|
||||
fetchFileVersions,
|
||||
updateCommentVersion,
|
||||
canChangeVersionFileHistory,
|
||||
|
||||
editing,
|
||||
setVerHistoryFileId,
|
||||
setVerHistoryFileAccess,
|
||||
setVerHistoryFileSecurity,
|
||||
};
|
||||
})(CommentEditor);
|
||||
|
@ -13,10 +13,6 @@ const User = ({
|
||||
updateRoomMemberRole,
|
||||
selectionParentRoom,
|
||||
setSelectionParentRoom,
|
||||
canChangeUserRoleInRoom,
|
||||
canDeleteUserInRoom,
|
||||
rootFolderType,
|
||||
access,
|
||||
}) => {
|
||||
if (!selectionParentRoom) return null;
|
||||
if (!user.displayName && !user.email) return null;
|
||||
@ -24,26 +20,11 @@ const User = ({
|
||||
const [userIsRemoved, setUserIsRemoved] = useState(false);
|
||||
if (userIsRemoved) return null;
|
||||
|
||||
const canChangeUserRole =
|
||||
user &&
|
||||
canChangeUserRoleInRoom({
|
||||
access,
|
||||
rootFolderType,
|
||||
currentUserInList: { id: user.id, access: user.access },
|
||||
});
|
||||
|
||||
const canDeleteUser =
|
||||
user &&
|
||||
canDeleteUserInRoom({
|
||||
access,
|
||||
rootFolderType,
|
||||
currentUserInList: { id: user.id, access: user.access },
|
||||
});
|
||||
const canChangeUserRole = user.canEditAccess;
|
||||
|
||||
const fullRoomRoleOptions = membersHelper.getOptionsByRoomType(
|
||||
selectionParentRoom.roomType,
|
||||
canChangeUserRole,
|
||||
canDeleteUser
|
||||
canChangeUserRole
|
||||
);
|
||||
|
||||
const userRole = membersHelper.getOptionByUserAccess(user.access);
|
||||
@ -103,7 +84,7 @@ const User = ({
|
||||
|
||||
{userRole && userRoleOptions && (
|
||||
<div className="role-wrapper">
|
||||
{canChangeUserRole || canDeleteUser ? (
|
||||
{canChangeUserRole ? (
|
||||
<ComboBox
|
||||
className="role-combobox"
|
||||
selectedOption={userRole}
|
||||
|
@ -30,29 +30,25 @@ const Members = ({
|
||||
|
||||
getRoomMembers,
|
||||
updateRoomMemberRole,
|
||||
|
||||
setView,
|
||||
roomsView,
|
||||
resendEmailInvitations,
|
||||
setInvitePanelOptions,
|
||||
canDeleteUserInRoom,
|
||||
changeUserType,
|
||||
canInviteUserInRoom,
|
||||
canChangeUserRoleInRoom,
|
||||
}) => {
|
||||
const membersHelper = new MembersHelper({ t });
|
||||
|
||||
const [members, setMembers] = useState(null);
|
||||
const [showLoader, setShowLoader] = useState(false);
|
||||
const { access, rootFolderType } = selection;
|
||||
|
||||
const canInviteUserInRoomAbility = canInviteUserInRoom({
|
||||
access,
|
||||
rootFolderType,
|
||||
});
|
||||
const security = selectionParentRoom ? selectionParentRoom.security : {};
|
||||
|
||||
const canInviteUserInRoomAbility = security?.EditAccess;
|
||||
|
||||
const fetchMembers = async (roomId) => {
|
||||
let timerId;
|
||||
if (members) timerId = setTimeout(() => setShowLoader(true), 1000);
|
||||
let data = await getRoomMembers(roomId);
|
||||
|
||||
data = data.filter((m) => m.sharedTo.email || m.sharedTo.displayName);
|
||||
clearTimeout(timerId);
|
||||
|
||||
@ -61,6 +57,7 @@ const Members = ({
|
||||
data.map((fetchedMember) => {
|
||||
const member = {
|
||||
access: fetchedMember.access,
|
||||
canEditAccess: fetchedMember.canEditAccess,
|
||||
...fetchedMember.sharedTo,
|
||||
};
|
||||
if (member.activationStatus !== 2) inRoomMembers.push(member);
|
||||
@ -98,6 +95,8 @@ const Members = ({
|
||||
...selection,
|
||||
members: fetchedMembers,
|
||||
});
|
||||
if (roomsView === "info_members" && !selection?.security?.Read)
|
||||
setView("info_details");
|
||||
}, [selection]);
|
||||
|
||||
useEffect(async () => {
|
||||
@ -162,8 +161,7 @@ const Members = ({
|
||||
<StyledUserList>
|
||||
{Object.values(members.inRoom).map((user) => (
|
||||
<User
|
||||
access={access}
|
||||
rootFolderType={rootFolderType}
|
||||
security={security}
|
||||
key={user.id}
|
||||
t={t}
|
||||
user={user}
|
||||
@ -174,8 +172,6 @@ const Members = ({
|
||||
roomType={selectionParentRoom.roomType}
|
||||
selectionParentRoom={selectionParentRoom}
|
||||
setSelectionParentRoom={setSelectionParentRoom}
|
||||
canChangeUserRoleInRoom={canChangeUserRoleInRoom}
|
||||
canDeleteUserInRoom={canDeleteUserInRoom}
|
||||
/>
|
||||
))}
|
||||
</StyledUserList>
|
||||
@ -199,8 +195,7 @@ const Members = ({
|
||||
<StyledUserList>
|
||||
{Object.values(members.expected).map((user) => (
|
||||
<User
|
||||
access={access}
|
||||
rootFolderType={rootFolderType}
|
||||
security={security}
|
||||
isExpect
|
||||
key={user.id}
|
||||
t={t}
|
||||
@ -212,8 +207,6 @@ const Members = ({
|
||||
roomType={selectionParentRoom.roomType}
|
||||
selectionParentRoom={selectionParentRoom}
|
||||
setSelectionParentRoom={setSelectionParentRoom}
|
||||
canDeleteUserInRoom={canDeleteUserInRoom}
|
||||
canChangeUserRoleInRoom={canChangeUserRoleInRoom}
|
||||
/>
|
||||
))}
|
||||
</StyledUserList>
|
||||
@ -226,7 +219,9 @@ export default inject(
|
||||
const {
|
||||
setIsMobileHidden,
|
||||
selectionParentRoom,
|
||||
|
||||
setSelectionParentRoom,
|
||||
setView,
|
||||
roomsView,
|
||||
|
||||
updateRoomMembers,
|
||||
@ -239,14 +234,10 @@ export default inject(
|
||||
} = filesStore;
|
||||
const { isOwner, isAdmin, id: selfId } = auth.userStore.user;
|
||||
const { setInvitePanelOptions } = dialogsStore;
|
||||
const { changeType: changeUserType } = peopleStore;
|
||||
const {
|
||||
canInviteUserInRoom,
|
||||
canChangeUserRoleInRoom,
|
||||
canDeleteUserInRoom,
|
||||
} = accessRightsStore;
|
||||
|
||||
return {
|
||||
setView,
|
||||
roomsView,
|
||||
setIsMobileHidden,
|
||||
selectionParentRoom,
|
||||
setSelectionParentRoom,
|
||||
@ -263,11 +254,6 @@ export default inject(
|
||||
|
||||
setInvitePanelOptions,
|
||||
resendEmailInvitations,
|
||||
|
||||
changeUserType,
|
||||
canInviteUserInRoom,
|
||||
canChangeUserRoleInRoom,
|
||||
canDeleteUserInRoom,
|
||||
};
|
||||
}
|
||||
)(
|
||||
|
@ -18,7 +18,6 @@ import { ColorTheme, ThemeType } from "@docspace/common/components/ColorTheme";
|
||||
|
||||
import { StyledInfoPanelHeader } from "./styles/common";
|
||||
import { FolderType } from "@docspace/common/constants";
|
||||
import { getArchiveRoomRoleActions } from "@docspace/common/utils/actions";
|
||||
|
||||
const InfoPanelHeaderContent = (props) => {
|
||||
const {
|
||||
@ -33,7 +32,7 @@ const InfoPanelHeaderContent = (props) => {
|
||||
getIsAccounts,
|
||||
isRootFolder,
|
||||
rootFolderType,
|
||||
canViewUsers,
|
||||
selectionParentRoom,
|
||||
} = props;
|
||||
|
||||
const isRooms = getIsRooms();
|
||||
@ -73,9 +72,12 @@ const InfoPanelHeaderContent = (props) => {
|
||||
content: null,
|
||||
},
|
||||
];
|
||||
const selectionRoomRights = selectionParentRoom
|
||||
? selectionParentRoom.security?.Read
|
||||
: selection?.security?.Read;
|
||||
|
||||
const roomsSubmenu = isArchiveRoot
|
||||
? canViewUsers(selection)
|
||||
? selectionRoomRights
|
||||
? [{ ...submenuData[0] }, { ...submenuData[2] }]
|
||||
: [{ ...submenuData[2] }]
|
||||
: [...submenuData];
|
||||
@ -144,9 +146,9 @@ export default inject(({ auth, selectedFolderStore, accessRightsStore }) => {
|
||||
getIsRooms,
|
||||
getIsGallery,
|
||||
getIsAccounts,
|
||||
selectionParentRoom,
|
||||
} = auth.infoPanelStore;
|
||||
const { isRootFolder, rootFolderType } = selectedFolderStore;
|
||||
const { canViewUsers } = accessRightsStore;
|
||||
|
||||
return {
|
||||
selection,
|
||||
@ -161,7 +163,8 @@ export default inject(({ auth, selectedFolderStore, accessRightsStore }) => {
|
||||
|
||||
isRootFolder,
|
||||
rootFolderType,
|
||||
canViewUsers,
|
||||
|
||||
selectionParentRoom,
|
||||
};
|
||||
})(
|
||||
withTranslation(["Common", "InfoPanel"])(
|
||||
|
@ -225,7 +225,7 @@ const SimpleFilesRow = (props) => {
|
||||
|
||||
const [isDragOver, setIsDragOver] = React.useState(false);
|
||||
|
||||
const withAccess = isAdmin || item.access === 0;
|
||||
const withAccess = item.security?.Lock;
|
||||
const isSmallContainer = sectionWidth <= 500;
|
||||
|
||||
const element = (
|
||||
|
@ -46,7 +46,7 @@ class PureHome extends React.Component {
|
||||
setFirstLoad,
|
||||
setToPreviewFile,
|
||||
playlist,
|
||||
isMediaOrImage,
|
||||
|
||||
getFileInfo,
|
||||
gallerySelected,
|
||||
setIsUpdatingRowItem,
|
||||
@ -68,7 +68,9 @@ class PureHome extends React.Component {
|
||||
setTimeout(() => {
|
||||
getFileInfo(fileId)
|
||||
.then((data) => {
|
||||
const canOpenPlayer = isMediaOrImage(data.fileExst);
|
||||
const canOpenPlayer =
|
||||
data.viewAccessability.ImageView ||
|
||||
data.viewAccessability.MediaView;
|
||||
const file = { ...data, canOpenPlayer };
|
||||
setToPreviewFile(file, true);
|
||||
})
|
||||
@ -465,6 +467,7 @@ class PureHome extends React.Component {
|
||||
isHeaderVisible,
|
||||
isPrivacyFolder,
|
||||
isRecycleBinFolder,
|
||||
isErrorRoomNotAvailable,
|
||||
|
||||
primaryProgressDataVisible,
|
||||
primaryProgressDataPercent,
|
||||
@ -525,13 +528,15 @@ class PureHome extends React.Component {
|
||||
onOpenUploadPanel={this.showUploadPanel}
|
||||
firstLoad={firstLoad}
|
||||
>
|
||||
<Section.SectionHeader>
|
||||
{isFrame ? (
|
||||
showTitle && <SectionHeaderContent />
|
||||
) : (
|
||||
<SectionHeaderContent />
|
||||
)}
|
||||
</Section.SectionHeader>
|
||||
{!isErrorRoomNotAvailable && (
|
||||
<Section.SectionHeader>
|
||||
{isFrame ? (
|
||||
showTitle && <SectionHeaderContent />
|
||||
) : (
|
||||
<SectionHeaderContent />
|
||||
)}
|
||||
</Section.SectionHeader>
|
||||
)}
|
||||
|
||||
{!isEmptyPage && (
|
||||
<Section.SectionFilter>
|
||||
@ -619,6 +624,7 @@ export default inject(
|
||||
isEmptyPage,
|
||||
|
||||
disableDrag,
|
||||
isErrorRoomNotAvailable,
|
||||
} = filesStore;
|
||||
|
||||
const { gallerySelected } = oformsStore;
|
||||
@ -721,7 +727,7 @@ export default inject(
|
||||
|
||||
itemsSelectionLength,
|
||||
itemsSelectionTitle,
|
||||
|
||||
isErrorRoomNotAvailable,
|
||||
isRoomsFolder,
|
||||
isArchiveFolder,
|
||||
|
||||
@ -744,7 +750,7 @@ export default inject(
|
||||
personal,
|
||||
setToPreviewFile,
|
||||
playlist,
|
||||
isMediaOrImage: settingsStore.isMediaOrImage,
|
||||
|
||||
getFileInfo,
|
||||
gallerySelected,
|
||||
setIsUpdatingRowItem,
|
||||
|
@ -114,8 +114,19 @@ const PortalRenaming = (props) => {
|
||||
setPortalRename(portalName)
|
||||
.then(() => toastr.success(t("SuccessfullySavePortalNameMessage")))
|
||||
.catch((error) => {
|
||||
setErrorValue(error);
|
||||
saveToSessionStorage("errorValue", error);
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
setErrorValue(errorMessage);
|
||||
saveToSessionStorage("errorValue", errorMessage);
|
||||
})
|
||||
.finally(() => setIsLoadingPortalNameSave(false));
|
||||
|
||||
|
@ -50,11 +50,22 @@ class PreparationPortal extends React.Component {
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) =>
|
||||
.catch((err) => {
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
err?.response?.data?.error?.message ||
|
||||
err?.statusText ||
|
||||
err?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = err;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
errorMessage: err,
|
||||
})
|
||||
);
|
||||
errorMessage: errorMessage,
|
||||
});
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.timerId);
|
||||
|
@ -220,44 +220,34 @@ const VersionRow = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({ auth, versionHistoryStore, accessRightsStore, selectedFolderStore }) => {
|
||||
const { user } = auth.userStore;
|
||||
const { culture, isTabletView } = auth.settingsStore;
|
||||
const language = (user && user.cultureName) || culture || "en";
|
||||
export default inject(({ auth, versionHistoryStore, selectedFolderStore }) => {
|
||||
const { user } = auth.userStore;
|
||||
const { culture, isTabletView } = auth.settingsStore;
|
||||
const language = (user && user.cultureName) || culture || "en";
|
||||
|
||||
const {
|
||||
markAsVersion,
|
||||
restoreVersion,
|
||||
updateCommentVersion,
|
||||
isEditing,
|
||||
isEditingVersion,
|
||||
fileAccess,
|
||||
} = versionHistoryStore;
|
||||
const {
|
||||
markAsVersion,
|
||||
restoreVersion,
|
||||
updateCommentVersion,
|
||||
isEditing,
|
||||
isEditingVersion,
|
||||
fileSecurity,
|
||||
} = versionHistoryStore;
|
||||
|
||||
const { rootFolderType } = selectedFolderStore;
|
||||
const isEdit = isEditingVersion || isEditing;
|
||||
const canChangeVersionFileHistory = !isEdit && fileSecurity?.EditHistory;
|
||||
|
||||
const isEdit = isEditingVersion || isEditing;
|
||||
const canChangeVersionFileHistory = accessRightsStore.canChangeVersionFileHistory(
|
||||
{
|
||||
access: fileAccess,
|
||||
rootFolderType,
|
||||
editing: isEdit,
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
theme: auth.settingsStore.theme,
|
||||
culture: language,
|
||||
isTabletView,
|
||||
markAsVersion,
|
||||
restoreVersion,
|
||||
updateCommentVersion,
|
||||
isEditing: isEdit,
|
||||
canChangeVersionFileHistory,
|
||||
};
|
||||
}
|
||||
)(
|
||||
return {
|
||||
theme: auth.settingsStore.theme,
|
||||
culture: language,
|
||||
isTabletView,
|
||||
markAsVersion,
|
||||
restoreVersion,
|
||||
updateCommentVersion,
|
||||
isEditing: isEdit,
|
||||
canChangeVersionFileHistory,
|
||||
};
|
||||
})(
|
||||
withRouter(
|
||||
withTranslation(["VersionHistory", "Common", "Translations"])(
|
||||
observer(VersionRow)
|
||||
|
@ -24,15 +24,15 @@ class SectionBodyContent extends React.Component {
|
||||
const fileId = match.params.fileId || this.props.fileId;
|
||||
|
||||
if (fileId && fileId !== this.props.fileId) {
|
||||
this.getFileVersions(fileId, fileAccess);
|
||||
this.getFileVersions(fileId, this.props.fileSecurity);
|
||||
setFirstLoad(false);
|
||||
}
|
||||
}
|
||||
|
||||
getFileVersions = (fileId, fileAccess) => {
|
||||
getFileVersions = (fileId, fileSecurity) => {
|
||||
const { fetchFileVersions, setIsLoading } = this.props;
|
||||
setIsLoading(true);
|
||||
fetchFileVersions(fileId, fileAccess).then(() => setIsLoading(false));
|
||||
fetchFileVersions(fileId, fileSecurity).then(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
onSetRestoreProcess = (restoring) => {
|
||||
@ -142,7 +142,7 @@ export default inject(({ auth, filesStore, versionHistoryStore }) => {
|
||||
versions,
|
||||
fetchFileVersions,
|
||||
fileId,
|
||||
fileAccess,
|
||||
fileSecurity,
|
||||
} = versionHistoryStore;
|
||||
|
||||
return {
|
||||
@ -150,7 +150,7 @@ export default inject(({ auth, filesStore, versionHistoryStore }) => {
|
||||
isLoading,
|
||||
versions,
|
||||
fileId,
|
||||
fileAccess,
|
||||
fileSecurity,
|
||||
setFirstLoad,
|
||||
setIsLoading,
|
||||
fetchFileVersions,
|
||||
|
@ -138,10 +138,20 @@ class Body extends Component {
|
||||
});
|
||||
setIsWizardLoaded(true);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
.catch((error) => {
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
console.error(errorMessage);
|
||||
this.setState({
|
||||
errorInitWizard: e,
|
||||
errorInitWizard: errorMessage,
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -246,13 +256,24 @@ class Body extends Component {
|
||||
.then(() =>
|
||||
history.push(combineUrl(AppServerConfig.proxyURL, "/login"))
|
||||
)
|
||||
.catch((e) =>
|
||||
.catch((error) => {
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
errorLoading: true,
|
||||
sending: false,
|
||||
errorMessage: e,
|
||||
})
|
||||
);
|
||||
errorMessage: errorMessage,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.setState({ visibleModal: true });
|
||||
}
|
||||
@ -382,13 +403,23 @@ class Body extends Component {
|
||||
let fd = new FormData();
|
||||
fd.append("files", file);
|
||||
|
||||
setLicense(wizardToken, fd).catch((e) =>
|
||||
setLicense(wizardToken, fd).catch((error) => {
|
||||
let errorMessage = "";
|
||||
if (typeof err === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
this.setState({
|
||||
errorLoading: true,
|
||||
errorMessage: e,
|
||||
errorMessage: errorMessage,
|
||||
hasErrorLicense: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -6,12 +6,6 @@ import {
|
||||
FolderType,
|
||||
ShareAccessRights,
|
||||
} from "@docspace/common/constants";
|
||||
import {
|
||||
getFileRoleActions,
|
||||
getRoomRoleActions,
|
||||
getArchiveRoomRoleActions,
|
||||
getArchiveFileRoleActions,
|
||||
} from "@docspace/common/utils/actions";
|
||||
|
||||
class AccessRightsStore {
|
||||
authStore = null;
|
||||
@ -25,281 +19,20 @@ class AccessRightsStore {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
canInviteUserInRoom(room) {
|
||||
const { access, rootFolderType } = room;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveRoomRoleActions(access).inviteUsers;
|
||||
|
||||
return getRoomRoleActions(access).inviteUsers;
|
||||
}
|
||||
|
||||
canChangeUserRoleInRoom = (room) => {
|
||||
const { access, rootFolderType, currentUserInList } = room;
|
||||
const { userStore } = this.authStore;
|
||||
const { user } = userStore;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveRoomRoleActions(access).changeUserRole;
|
||||
|
||||
const isMyProfile = user.id === currentUserInList.id;
|
||||
const isOwnerRoleRoom =
|
||||
currentUserInList.access === ShareAccessRights.FullAccess;
|
||||
|
||||
if (isMyProfile || isOwnerRoleRoom) return false;
|
||||
|
||||
return getRoomRoleActions(access).changeUserRole;
|
||||
};
|
||||
canDeleteUserInRoom = (room) => {
|
||||
const { access, currentUserInList, rootFolderType } = room;
|
||||
const { userStore } = this.authStore;
|
||||
const { user } = userStore;
|
||||
|
||||
const isMyProfile = user.id === currentUserInList.id;
|
||||
const isOwnerRoleRoom =
|
||||
currentUserInList.access === ShareAccessRights.FullAccess;
|
||||
|
||||
if (isMyProfile || isOwnerRoleRoom) return false;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveRoomRoleActions(access).deleteUsers;
|
||||
|
||||
return getRoomRoleActions(access).deleteUsers;
|
||||
};
|
||||
canLockFile = (file) => {
|
||||
const { rootFolderType, access } = file;
|
||||
|
||||
if (rootFolderType === FolderType.USER) return false;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).block;
|
||||
|
||||
if (rootFolderType === FolderType.TRASH) return false;
|
||||
|
||||
return getFileRoleActions(access).block;
|
||||
};
|
||||
|
||||
canChangeVersionFileHistory = (file) => {
|
||||
const { rootFolderType, editing, providerKey, access } = file;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).changeVersionHistory;
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH ||
|
||||
// rootFolderType === FolderType.Privacy ||
|
||||
editing ||
|
||||
providerKey
|
||||
)
|
||||
return false;
|
||||
|
||||
return getFileRoleActions(access).changeVersionHistory;
|
||||
};
|
||||
canViewVersionFileHistory = (file) => {
|
||||
const { rootFolderType, access, providerKey } = file;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).viewVersionHistory;
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH ||
|
||||
// rootFolderType === FolderType.Privacy ||
|
||||
providerKey
|
||||
)
|
||||
return false;
|
||||
|
||||
return getFileRoleActions(access).viewVersionHistory;
|
||||
};
|
||||
|
||||
canEditFile = (file) => {
|
||||
const { rootFolderType, access } = file;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).edit;
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH
|
||||
// || rootFolderType === FolderType.Privacy
|
||||
)
|
||||
return false;
|
||||
|
||||
return getFileRoleActions(access).edit;
|
||||
};
|
||||
|
||||
canRenameItem = (item = {}) => {
|
||||
const { rootFolderType, access, isFile } = item;
|
||||
const { isDesktopClient } = this.authStore.settingsStore;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).rename;
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH
|
||||
// ||
|
||||
// (!isFile && rootFolderType === FolderType.Privacy && !isDesktopClient)
|
||||
)
|
||||
return false;
|
||||
|
||||
return getFileRoleActions(access).rename;
|
||||
};
|
||||
canFillForm = (file) => {
|
||||
const { rootFolderType, access } = file;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).fillForm;
|
||||
|
||||
if (rootFolderType === FolderType.TRASH) return false;
|
||||
|
||||
return getFileRoleActions(access).fillForm;
|
||||
};
|
||||
|
||||
canMakeForm = (item) => {
|
||||
const { rootFolderType, access } = item;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).saveAsForm;
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH ||
|
||||
// rootFolderType === FolderType.Privacy ||
|
||||
rootFolderType === FolderType.Favorites ||
|
||||
rootFolderType === FolderType.Recent
|
||||
)
|
||||
return false;
|
||||
|
||||
return getFileRoleActions(access).saveAsForm;
|
||||
};
|
||||
|
||||
canArchiveRoom = (room) => {
|
||||
const { archive } = getRoomRoleActions(room.access);
|
||||
|
||||
return archive;
|
||||
};
|
||||
|
||||
canRemoveRoom = (room) => {
|
||||
const { access, rootFolderType } = room;
|
||||
|
||||
if (rootFolderType !== FolderType.Archive)
|
||||
return getRoomRoleActions(access).delete;
|
||||
|
||||
return getArchiveRoomRoleActions(access).delete;
|
||||
};
|
||||
|
||||
canViewRoomInfo = (room) => {
|
||||
const { access, rootFolderType } = room;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveRoomRoleActions(access).viewInfo;
|
||||
|
||||
return getRoomRoleActions(access).viewInfo;
|
||||
};
|
||||
|
||||
canPinRoom = (room) => {
|
||||
const { access, rootFolderType } = room;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveRoomRoleActions(access).canPin;
|
||||
|
||||
return getRoomRoleActions(access).canPin;
|
||||
};
|
||||
|
||||
canEditRoom = (room) => {
|
||||
const { access, rootFolderType } = room;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveRoomRoleActions(access).edit;
|
||||
|
||||
return getRoomRoleActions(access).edit;
|
||||
};
|
||||
|
||||
get canCreateFiles() {
|
||||
const { access, rootFolderType } = this.selectedFolderStore;
|
||||
const { security } = this.selectedFolderStore;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).create;
|
||||
|
||||
const { create } = getFileRoleActions(access);
|
||||
|
||||
return create;
|
||||
return security?.Create;
|
||||
}
|
||||
|
||||
canMoveItems = (item) => {
|
||||
const { rootFolderType, access, editing: fileEditing, providerKey } = item;
|
||||
const { editing: fileEditing, security, rootFolderType } = item;
|
||||
|
||||
if (rootFolderType === FolderType.Archive) {
|
||||
const { moveSelf, moveAlien } = getArchiveFileRoleActions(access);
|
||||
if (rootFolderType === FolderType.TRASH || fileEditing) return false;
|
||||
|
||||
return moveSelf || moveAlien;
|
||||
}
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH ||
|
||||
rootFolderType === FolderType.Favorites ||
|
||||
rootFolderType === FolderType.Recent ||
|
||||
// rootFolderType === FolderType.Privacy ||
|
||||
providerKey ||
|
||||
fileEditing
|
||||
)
|
||||
return false;
|
||||
|
||||
const { moveSelf, moveAlien } = getFileRoleActions(access);
|
||||
|
||||
return moveSelf || moveAlien;
|
||||
return security?.Move;
|
||||
};
|
||||
|
||||
canDeleteItems = (item) => {
|
||||
const { rootFolderType, access, editing: fileEditing } = item;
|
||||
|
||||
if (rootFolderType === FolderType.Archive) {
|
||||
const { deleteSelf, deleteAlien } = getArchiveFileRoleActions(access);
|
||||
|
||||
return deleteSelf || deleteAlien;
|
||||
}
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.Favorites ||
|
||||
rootFolderType === FolderType.Recent ||
|
||||
// rootFolderType === FolderType.Privacy ||
|
||||
fileEditing
|
||||
)
|
||||
return false;
|
||||
|
||||
const { deleteSelf, deleteAlien } = getFileRoleActions(access);
|
||||
|
||||
return deleteSelf || deleteAlien;
|
||||
};
|
||||
|
||||
canCopyItems = (item) => {
|
||||
const { rootFolderType, access } = item;
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH ||
|
||||
rootFolderType === FolderType.Favorites ||
|
||||
rootFolderType === FolderType.Recent
|
||||
// || rootFolderType === FolderType.Privacy
|
||||
)
|
||||
return false;
|
||||
|
||||
const { canCopy } = getFileRoleActions(access);
|
||||
|
||||
return canCopy;
|
||||
};
|
||||
canDuplicateFile = (item) => {
|
||||
const { rootFolderType, access } = item;
|
||||
|
||||
if (rootFolderType === FolderType.Archive)
|
||||
return getArchiveFileRoleActions(access).canDuplicate;
|
||||
|
||||
if (
|
||||
rootFolderType === FolderType.TRASH ||
|
||||
rootFolderType === FolderType.Favorites ||
|
||||
rootFolderType === FolderType.Recent
|
||||
// || rootFolderType === FolderType.Privacy
|
||||
)
|
||||
return false;
|
||||
|
||||
return getFileRoleActions(access).canDuplicate;
|
||||
};
|
||||
canChangeUserType = (user) => {
|
||||
const { id, isOwner } = this.authStore.userStore.user;
|
||||
|
||||
@ -423,19 +156,6 @@ class AccessRightsStore {
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
canViewUsers = (room) => {
|
||||
const { rootFolderType } = this.selectedFolderStore;
|
||||
|
||||
if (!room) return false;
|
||||
|
||||
const options =
|
||||
rootFolderType === FolderType.Archive
|
||||
? getArchiveRoomRoleActions(room.access)
|
||||
: getRoomRoleActions(room.access);
|
||||
|
||||
return options.viewUsers;
|
||||
};
|
||||
}
|
||||
|
||||
export default AccessRightsStore;
|
||||
|
@ -163,7 +163,7 @@ class ContextOptionsStore {
|
||||
this.dialogsStore.setCopyPanelVisible(true);
|
||||
};
|
||||
|
||||
showVersionHistory = (id) => {
|
||||
showVersionHistory = (id, security) => {
|
||||
const {
|
||||
fetchFileVersions,
|
||||
setIsVerHistoryPanel,
|
||||
@ -171,7 +171,7 @@ class ContextOptionsStore {
|
||||
|
||||
if (this.treeFoldersStore.isRecycleBinFolder) return;
|
||||
|
||||
fetchFileVersions(id + "");
|
||||
fetchFileVersions(id + "", security);
|
||||
setIsVerHistoryPanel(true);
|
||||
};
|
||||
|
||||
@ -257,7 +257,7 @@ class ContextOptionsStore {
|
||||
|
||||
onClickLinkEdit = (item) => {
|
||||
const { setConvertItem, setConvertDialogVisible } = this.dialogsStore;
|
||||
const canConvert = this.settingsStore.canConvert(item.fileExst);
|
||||
const canConvert = item.viewAccessability?.Convert;
|
||||
|
||||
if (canConvert) {
|
||||
setConvertItem(item);
|
||||
@ -497,8 +497,9 @@ class ContextOptionsStore {
|
||||
const isRootRoom = item.isRoom && rootFolderId === id;
|
||||
const isShareable = item.canShare;
|
||||
|
||||
const isMedia = this.settingsStore.isMediaOrImage(item.fileExst);
|
||||
const isCanWebEdit = this.settingsStore.canWebEdit(item.fileExst);
|
||||
const isMedia =
|
||||
item.viewAccessability?.ImageView || item.viewAccessability?.MediaView;
|
||||
const isCanWebEdit = item.viewAccessability?.WebEdit;
|
||||
const hasInfoPanel = contextOptions.includes("show-info");
|
||||
|
||||
const emailSendIsDisabled = true;
|
||||
@ -535,7 +536,7 @@ class ContextOptionsStore {
|
||||
key: "show-version-history",
|
||||
label: t("ShowVersionHistory"),
|
||||
icon: "images/history.react.svg",
|
||||
onClick: () => this.showVersionHistory(item.id, item.access),
|
||||
onClick: () => this.showVersionHistory(item.id, item.security),
|
||||
disabled: false,
|
||||
},
|
||||
]
|
||||
@ -551,7 +552,7 @@ class ContextOptionsStore {
|
||||
key: "finalize-version",
|
||||
label: t("FinalizeVersion"),
|
||||
icon: "images/history-finalized.react.svg",
|
||||
onClick: () => this.finalizeVersion(item.id, item.access),
|
||||
onClick: () => this.finalizeVersion(item.id, item.security),
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
@ -560,7 +561,7 @@ class ContextOptionsStore {
|
||||
label: t("ShowVersionHistory"),
|
||||
icon: "images/history.react.svg",
|
||||
onClick: () =>
|
||||
this.showVersionHistory(item.id, item.access),
|
||||
this.showVersionHistory(item.id, item.security),
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
@ -580,7 +581,7 @@ class ContextOptionsStore {
|
||||
key: "show-version-history",
|
||||
label: t("ShowVersionHistory"),
|
||||
icon: "images/history.react.svg",
|
||||
onClick: () => this.showVersionHistory(item.id, item.access),
|
||||
onClick: () => this.showVersionHistory(item.id, item.security),
|
||||
disabled: false,
|
||||
},
|
||||
]
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
ConflictResolveType,
|
||||
FileAction,
|
||||
FileStatus,
|
||||
FolderType,
|
||||
} from "@docspace/common/constants";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import { isMobile } from "react-device-detect";
|
||||
@ -1275,18 +1276,11 @@ class FilesActionStore {
|
||||
selection,
|
||||
} = this.filesStore;
|
||||
|
||||
const {
|
||||
canCopyItems,
|
||||
canDeleteItems,
|
||||
canMoveItems,
|
||||
canArchiveRoom,
|
||||
canRemoveRoom,
|
||||
} = this.accessRightsStore;
|
||||
const { access, rootFolderType } = this.selectedFolderStore;
|
||||
const { rootFolderType } = this.selectedFolderStore;
|
||||
|
||||
switch (option) {
|
||||
case "copy":
|
||||
const canCopy = canCopyItems({ access, rootFolderType });
|
||||
const canCopy = selection.map((s) => s.security?.Copy).filter((s) => s);
|
||||
|
||||
return hasSelection && canCopy;
|
||||
case "showInfo":
|
||||
@ -1295,35 +1289,33 @@ class FilesActionStore {
|
||||
case "downloadAs":
|
||||
return canConvertSelected;
|
||||
case "moveTo":
|
||||
const canMove = canMoveItems({
|
||||
access,
|
||||
rootFolderType,
|
||||
editing: allFilesIsEditing,
|
||||
});
|
||||
return hasSelection && canMove;
|
||||
const canMove = selection.every((s) => s.security?.Move);
|
||||
|
||||
return (
|
||||
hasSelection &&
|
||||
!allFilesIsEditing &&
|
||||
canMove &&
|
||||
rootFolderType !== FolderType.TRASH
|
||||
);
|
||||
|
||||
case "archive":
|
||||
case "unarchive":
|
||||
const canArchive = selection
|
||||
.map((s) => canArchiveRoom(s))
|
||||
.map((s) => s.security?.Move)
|
||||
.filter((s) => s);
|
||||
|
||||
return canArchive.length > 0;
|
||||
case "delete-room":
|
||||
const canRemove = selection
|
||||
.map((s) => canRemoveRoom(s))
|
||||
.map((s) => s.security?.Delete)
|
||||
.filter((r) => r);
|
||||
|
||||
return canRemove.length > 0;
|
||||
|
||||
case "delete":
|
||||
const canDelete = canDeleteItems({
|
||||
access,
|
||||
rootFolderType,
|
||||
editing: allFilesIsEditing,
|
||||
});
|
||||
const canDelete = selection.every((s) => s.security?.Delete);
|
||||
|
||||
return canDelete && hasSelection;
|
||||
return !allFilesIsEditing && canDelete && hasSelection;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1778,10 +1770,11 @@ class FilesActionStore {
|
||||
const { setMediaViewerData } = this.mediaViewerDataStore;
|
||||
const { setConvertDialogVisible, setConvertItem } = this.dialogsStore;
|
||||
|
||||
const isMediaOrImage = this.settingsStore.isMediaOrImage(item.fileExst);
|
||||
const canConvert = this.settingsStore.canConvert(item.fileExst);
|
||||
const canWebEdit = this.settingsStore.canWebEdit(item.fileExst);
|
||||
const canViewedDocs = this.settingsStore.canViewedDocs(item.fileExst);
|
||||
const isMediaOrImage =
|
||||
item.viewAccessability?.ImageView || item.viewAccessability?.MediaView;
|
||||
const canConvert = item.viewAccessability?.Convert;
|
||||
const canWebEdit = item.viewAccessability?.WebEdit;
|
||||
const canViewedDocs = item.viewAccessability?.WebView;
|
||||
|
||||
const { id, viewUrl, providerKey, fileStatus, encrypted, isFolder } = item;
|
||||
if (encrypted && isPrivacyFolder) return checkProtocol(item.id, true);
|
||||
|
@ -26,7 +26,6 @@ import {
|
||||
import { isDesktop } from "@docspace/components/utils/device";
|
||||
import { getContextMenuKeysByType } from "SRC_DIR/helpers/plugins";
|
||||
import { PluginContextMenuItemType } from "SRC_DIR/helpers/plugins/constants";
|
||||
import { getArchiveRoomRoleActions } from "@docspace/common/utils/actions";
|
||||
import debounce from "lodash.debounce";
|
||||
|
||||
const { FilesFilter, RoomsFilter } = api;
|
||||
@ -34,6 +33,11 @@ const storageViewAs = localStorage.getItem("viewAs");
|
||||
|
||||
let requestCounter = 0;
|
||||
|
||||
const NotFoundHttpCode = 404;
|
||||
const ForbiddenHttpCode = 403;
|
||||
const PaymentRequiredHttpCode = 402;
|
||||
const UnauthorizedHttpCode = 401;
|
||||
|
||||
class FilesStore {
|
||||
authStore;
|
||||
|
||||
@ -102,6 +106,8 @@ class FilesStore {
|
||||
tempActionFilesIds = [];
|
||||
operationAction = false;
|
||||
|
||||
isErrorRoomNotAvailable = false;
|
||||
|
||||
constructor(
|
||||
authStore,
|
||||
selectedFolderStore,
|
||||
@ -809,6 +815,7 @@ class FilesStore {
|
||||
if (folderId === "@my" && this.authStore.userStore.user.isVisitor)
|
||||
return this.fetchRooms();
|
||||
|
||||
this.isErrorRoomNotAvailable = false;
|
||||
this.isLoadedFetchFiles = false;
|
||||
|
||||
const filterStorageItem =
|
||||
@ -951,18 +958,23 @@ class FilesStore {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
toastr.error(err);
|
||||
|
||||
if (requestCounter > 0) return;
|
||||
|
||||
requestCounter++;
|
||||
setTimeout(() => {
|
||||
window.location.href = combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
config.homepage,
|
||||
"/rooms/shared/"
|
||||
);
|
||||
}, 5000);
|
||||
const isUserError = [
|
||||
NotFoundHttpCode,
|
||||
ForbiddenHttpCode,
|
||||
PaymentRequiredHttpCode,
|
||||
UnauthorizedHttpCode,
|
||||
].includes(err?.response?.status);
|
||||
|
||||
if (isUserError) {
|
||||
this.isErrorRoomNotAvailable = true;
|
||||
this.isEmptyPage = true;
|
||||
} else {
|
||||
toastr.error(err);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoadedFetchFiles = true;
|
||||
@ -1066,7 +1078,7 @@ class FilesStore {
|
||||
|
||||
this.setCreatedItem(null);
|
||||
}
|
||||
|
||||
this.isErrorRoomNotAvailable = false;
|
||||
return Promise.resolve(selectedFolder);
|
||||
})
|
||||
.catch((err) => {
|
||||
@ -1136,7 +1148,7 @@ class FilesStore {
|
||||
return newOptions.filter((o) => o);
|
||||
};
|
||||
|
||||
getFilesContextOptions = (item, canOpenPlayer) => {
|
||||
getFilesContextOptions = (item) => {
|
||||
const isFile = !!item.fileExst || item.contentLength;
|
||||
const isRoom = !!item.roomType;
|
||||
const isFavorite =
|
||||
@ -1155,8 +1167,6 @@ class FilesStore {
|
||||
|
||||
const { isRecycleBinFolder, isMy, isArchiveFolder } = this.treeFoldersStore;
|
||||
|
||||
const { canFormFillingDocs } = this.filesSettingsStore;
|
||||
|
||||
const { enablePlugins } = this.authStore.settingsStore;
|
||||
|
||||
const isThirdPartyFolder =
|
||||
@ -1169,39 +1179,33 @@ class FilesStore {
|
||||
const pluginAllKeys =
|
||||
enablePlugins && getContextMenuKeysByType(PluginContextMenuItemType.All);
|
||||
|
||||
const canRenameItem = this.accessRightsStore.canRenameItem({
|
||||
...item,
|
||||
...isFile,
|
||||
});
|
||||
const canRenameItem = item.security?.Rename;
|
||||
|
||||
const canMove = this.accessRightsStore.canMoveItems({
|
||||
...item,
|
||||
...{ editing: isEditing },
|
||||
});
|
||||
|
||||
const canDelete = this.accessRightsStore.canDeleteItems({
|
||||
...item,
|
||||
...{ editing: isEditing },
|
||||
});
|
||||
const canDelete = !isEditing && item.security?.Delete;
|
||||
|
||||
const canCopy = this.accessRightsStore.canCopyItems(item);
|
||||
const canCreateCopy = this.accessRightsStore.canDuplicateFile(item);
|
||||
const canCopy = item.security?.Copy;
|
||||
const canDuplicate = item.security?.Duplicate;
|
||||
|
||||
if (isFile) {
|
||||
const shouldFillForm = canFormFillingDocs(item.fileExst);
|
||||
const canLockFile = this.accessRightsStore.canLockFile(item);
|
||||
const canChangeVersionFileHistory = this.accessRightsStore.canChangeVersionFileHistory(
|
||||
{ ...item, ...{ editing: isEditing } }
|
||||
);
|
||||
const shouldFillForm = item.viewAccessability.WebRestrictedEditing;
|
||||
const canLockFile = item.security?.Lock;
|
||||
const canChangeVersionFileHistory =
|
||||
!isEditing && item.security?.EditHistory;
|
||||
|
||||
const canViewVersionFileHistory = this.accessRightsStore.canViewVersionFileHistory(
|
||||
item
|
||||
);
|
||||
const canFillForm = this.accessRightsStore.canFillForm(item);
|
||||
const canViewVersionFileHistory = item.security?.ReadHistory;
|
||||
const canFillForm = item.security?.FillForms;
|
||||
|
||||
const canEditFile = item.security.Edit && item.viewAccessability.WebEdit;
|
||||
const canOpenPlayer =
|
||||
item.viewAccessability.ImageView || item.viewAccessability.MediaView;
|
||||
const canViewFile = item.viewAccessability.WebView;
|
||||
|
||||
const canEditFile = this.accessRightsStore.canEditFile(item);
|
||||
const isMasterForm = item.fileExst === ".docxf";
|
||||
const canMakeForm = this.accessRightsStore.canMakeForm(item);
|
||||
|
||||
let fileOptions = [
|
||||
//"open",
|
||||
@ -1288,14 +1292,14 @@ class FilesStore {
|
||||
fileOptions = this.removeOptions(fileOptions, ["copy-to"]);
|
||||
}
|
||||
|
||||
if (!canCreateCopy) {
|
||||
if (!canDuplicate) {
|
||||
fileOptions = this.removeOptions(fileOptions, ["copy"]);
|
||||
}
|
||||
if (!canMove && !canCopy && !canCreateCopy) {
|
||||
if (!canMove && !canCopy && !canDuplicate) {
|
||||
fileOptions = this.removeOptions(fileOptions, ["move"]);
|
||||
}
|
||||
|
||||
if (!(isMasterForm && canMakeForm))
|
||||
if (!(isMasterForm && canDuplicate))
|
||||
fileOptions = this.removeOptions(fileOptions, ["make-form"]);
|
||||
|
||||
if (item.rootFolderType === FolderType.Archive) {
|
||||
@ -1314,10 +1318,12 @@ class FilesStore {
|
||||
fileOptions = this.removeOptions(fileOptions, ["convert"]);
|
||||
}
|
||||
|
||||
if (!canViewFile || isRecycleBinFolder) {
|
||||
fileOptions = this.removeOptions(fileOptions, ["preview"]);
|
||||
}
|
||||
|
||||
if (!canOpenPlayer) {
|
||||
fileOptions = this.removeOptions(fileOptions, ["view"]);
|
||||
} else {
|
||||
fileOptions = this.removeOptions(fileOptions, ["preview"]);
|
||||
}
|
||||
|
||||
if (!isDocuSign) {
|
||||
@ -1363,36 +1369,20 @@ class FilesStore {
|
||||
// ]);
|
||||
// }
|
||||
|
||||
if (isRecycleBinFolder) {
|
||||
if (!isRecycleBinFolder)
|
||||
fileOptions = this.removeOptions(fileOptions, [
|
||||
"open",
|
||||
"open-location",
|
||||
"view",
|
||||
"preview",
|
||||
"restore",
|
||||
"link-for-room-members",
|
||||
//"link-for-portal-users",
|
||||
//"sharing-settings",
|
||||
//"external-link",
|
||||
"send-by-email",
|
||||
"mark-read",
|
||||
// "mark-as-favorite",
|
||||
// "remove-from-favorites",
|
||||
"separator0",
|
||||
"separator1",
|
||||
]);
|
||||
} else {
|
||||
fileOptions = this.removeOptions(fileOptions, ["restore"]);
|
||||
|
||||
if (enablePlugins) {
|
||||
const pluginFilesKeys = getContextMenuKeysByType(
|
||||
PluginContextMenuItemType.Files
|
||||
);
|
||||
if (enablePlugins && !isRecycleBinFolder) {
|
||||
const pluginFilesKeys = getContextMenuKeysByType(
|
||||
PluginContextMenuItemType.Files
|
||||
);
|
||||
|
||||
pluginAllKeys &&
|
||||
pluginAllKeys.forEach((key) => fileOptions.push(key));
|
||||
pluginFilesKeys &&
|
||||
pluginFilesKeys.forEach((key) => fileOptions.push(key));
|
||||
}
|
||||
pluginAllKeys && pluginAllKeys.forEach((key) => fileOptions.push(key));
|
||||
pluginFilesKeys &&
|
||||
pluginFilesKeys.forEach((key) => fileOptions.push(key));
|
||||
}
|
||||
|
||||
if (!this.canShareOwnerChange(item)) {
|
||||
@ -1440,17 +1430,15 @@ class FilesStore {
|
||||
|
||||
return fileOptions;
|
||||
} else if (isRoom) {
|
||||
const canInviteUserInRoom = this.accessRightsStore.canInviteUserInRoom(
|
||||
item
|
||||
);
|
||||
const canRemoveRoom = this.accessRightsStore.canRemoveRoom(item);
|
||||
const canInviteUserInRoom = item.security?.EditAccess;
|
||||
const canRemoveRoom = item.security?.Delete;
|
||||
|
||||
const canArchiveRoom = this.accessRightsStore.canArchiveRoom(item);
|
||||
const canPinRoom = this.accessRightsStore.canPinRoom(item);
|
||||
const canArchiveRoom = item.security?.Move;
|
||||
const canPinRoom = item.security?.Pin;
|
||||
|
||||
const canEditRoom = this.accessRightsStore.canEditRoom(item);
|
||||
const canEditRoom = item.security?.EditRoom;
|
||||
|
||||
const canViewRoomInfo = this.accessRightsStore.canViewRoomInfo(item);
|
||||
const canViewRoomInfo = item.security?.Read;
|
||||
|
||||
let roomOptions = [
|
||||
"select",
|
||||
@ -1576,11 +1564,11 @@ class FilesStore {
|
||||
folderOptions = this.removeOptions(folderOptions, ["copy-to"]);
|
||||
}
|
||||
|
||||
if (!canCreateCopy) {
|
||||
if (!canDuplicate) {
|
||||
folderOptions = this.removeOptions(folderOptions, ["copy"]);
|
||||
}
|
||||
|
||||
if (!canMove && !canCopy && !canCreateCopy) {
|
||||
if (!canMove && !canCopy && !canDuplicate) {
|
||||
folderOptions = this.removeOptions(folderOptions, ["move"]);
|
||||
}
|
||||
|
||||
@ -2128,6 +2116,8 @@ class FilesStore {
|
||||
isArchive,
|
||||
tags,
|
||||
pinned,
|
||||
security,
|
||||
viewAccessability,
|
||||
} = item;
|
||||
|
||||
const thirdPartyIcon = this.thirdPartyStore.getThirdPartyIcon(
|
||||
@ -2140,9 +2130,8 @@ class FilesStore {
|
||||
Object.keys(RoomsProviderType).find((key) => key === item.providerKey)
|
||||
];
|
||||
|
||||
const { canConvert, isMediaOrImage } = this.filesSettingsStore;
|
||||
|
||||
const canOpenPlayer = isMediaOrImage(item.fileExst);
|
||||
const canOpenPlayer =
|
||||
item.viewAccessability?.ImageView || item.viewAccessability?.MediaView;
|
||||
|
||||
const previewUrl = canOpenPlayer
|
||||
? this.getItemUrl(id, false, needConvert, canOpenPlayer)
|
||||
@ -2161,7 +2150,7 @@ class FilesStore {
|
||||
|
||||
const folderUrl = isFolder && this.getItemUrl(id, isFolder, false, false);
|
||||
|
||||
const needConvert = canConvert(fileExst);
|
||||
const needConvert = item.viewAccessability?.Convert;
|
||||
const isEditing =
|
||||
(item.fileStatus & FileStatus.IsEditing) === FileStatus.IsEditing;
|
||||
|
||||
@ -2244,6 +2233,8 @@ class FilesStore {
|
||||
pinned,
|
||||
thirdPartyIcon,
|
||||
providerType,
|
||||
security,
|
||||
viewAccessability,
|
||||
};
|
||||
});
|
||||
|
||||
@ -2252,8 +2243,6 @@ class FilesStore {
|
||||
|
||||
get cbMenuItems() {
|
||||
const {
|
||||
isImage,
|
||||
isVideo,
|
||||
isDocument,
|
||||
isPresentation,
|
||||
isSpreadsheet,
|
||||
@ -2293,8 +2282,10 @@ class FilesStore {
|
||||
cbMenu.push(FilterType.PresentationsOnly);
|
||||
else if (isSpreadsheet(item.fileExst))
|
||||
cbMenu.push(FilterType.SpreadsheetsOnly);
|
||||
else if (isImage(item.fileExst)) cbMenu.push(FilterType.ImagesOnly);
|
||||
else if (isVideo(item.fileExst)) cbMenu.push(FilterType.MediaOnly);
|
||||
else if (item.viewAccessability?.ImageView)
|
||||
cbMenu.push(FilterType.ImagesOnly);
|
||||
else if (item.viewAccessability?.MediaView)
|
||||
cbMenu.push(FilterType.MediaOnly);
|
||||
else if (isArchive(item.fileExst)) cbMenu.push(FilterType.ArchiveOnly);
|
||||
}
|
||||
|
||||
@ -2489,20 +2480,19 @@ class FilesStore {
|
||||
}
|
||||
|
||||
get isViewedSelected() {
|
||||
const { canViewedDocs } = this.filesSettingsStore;
|
||||
|
||||
return this.selection.some((selected) => {
|
||||
if (selected.isFolder === true || !selected.fileExst) return false;
|
||||
return canViewedDocs(selected.fileExst);
|
||||
return selected.viewAccessability?.WebView;
|
||||
});
|
||||
}
|
||||
|
||||
get isMediaSelected() {
|
||||
const { isMediaOrImage } = this.filesSettingsStore;
|
||||
|
||||
return this.selection.some((selected) => {
|
||||
if (selected.isFolder === true || !selected.fileExst) return false;
|
||||
return isMediaOrImage(selected.fileExst);
|
||||
return (
|
||||
selected.viewAccessability?.ImageView ||
|
||||
selected.viewAccessability?.MediaView
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -2543,15 +2533,6 @@ class FilesStore {
|
||||
}
|
||||
|
||||
getOptions = (selection, externalAccess = false) => {
|
||||
const {
|
||||
canWebEdit,
|
||||
canWebComment,
|
||||
canWebReview,
|
||||
canFormFillingDocs,
|
||||
canWebFilterEditing,
|
||||
canConvert,
|
||||
} = this.filesSettingsStore;
|
||||
|
||||
if (selection[0].encrypted) {
|
||||
return ["FullAccess", "DenyAccess"];
|
||||
}
|
||||
@ -2560,19 +2541,21 @@ class FilesStore {
|
||||
|
||||
AccessOptions.push("ReadOnly", "DenyAccess");
|
||||
|
||||
const webEdit = selection.find((x) => canWebEdit(x.fileExst));
|
||||
const webEdit = selection.find((x) => x.viewAccessability?.WebEdit);
|
||||
|
||||
const webComment = selection.find((x) => canWebComment(x.fileExst));
|
||||
const webComment = selection.find((x) => x.viewAccessability?.WebComment);
|
||||
|
||||
const webReview = selection.find((x) => canWebReview(x.fileExst));
|
||||
const webReview = selection.find((x) => x.viewAccessability?.WebReview);
|
||||
|
||||
const formFillingDocs = selection.find((x) =>
|
||||
canFormFillingDocs(x.fileExst)
|
||||
const formFillingDocs = selection.find(
|
||||
(x) => x.viewAccessability?.WebRestrictedEditing
|
||||
);
|
||||
|
||||
const webFilter = selection.find((x) => canWebFilterEditing(x.fileExst));
|
||||
const webFilter = selection.find(
|
||||
(x) => x.viewAccessability?.WebCustomFilterEditing
|
||||
);
|
||||
|
||||
const webNeedConvert = selection.find((x) => canConvert(x.fileExst));
|
||||
const webNeedConvert = selection.find((x) => x.viewAccessability?.Convert);
|
||||
|
||||
if ((webEdit && !webNeedConvert) || !externalAccess)
|
||||
AccessOptions.push("FullAccess");
|
||||
@ -2897,15 +2880,11 @@ class FilesStore {
|
||||
}
|
||||
|
||||
get roomsForRestore() {
|
||||
return this.folders.filter(
|
||||
(f) => getArchiveRoomRoleActions(f.access).restore
|
||||
);
|
||||
return this.folders.filter((f) => f.security.Move);
|
||||
}
|
||||
|
||||
get roomsForDelete() {
|
||||
return this.folders.filter(
|
||||
(f) => getArchiveRoomRoleActions(f.access).delete
|
||||
);
|
||||
return this.folders.filter((f) => f.security.Delete);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,6 @@ class MediaViewerDataStore {
|
||||
};
|
||||
|
||||
get playlist() {
|
||||
const { isMediaOrImage } = this.settingsStore;
|
||||
const { files } = this.filesStore;
|
||||
|
||||
const filesList = [...files];
|
||||
@ -66,7 +65,8 @@ class MediaViewerDataStore {
|
||||
|
||||
if (filesList.length > 0) {
|
||||
filesList.forEach((file) => {
|
||||
const canOpenPlayer = isMediaOrImage(file.fileExst);
|
||||
const canOpenPlayer =
|
||||
file.viewAccessability.ImageView || file.viewAccessability.MediaView;
|
||||
if (canOpenPlayer) {
|
||||
playlist.push({
|
||||
id: id,
|
||||
|
@ -29,6 +29,7 @@ class SelectedFolderStore {
|
||||
tags = null;
|
||||
rootFolderId = null;
|
||||
settingsStore = null;
|
||||
security = null;
|
||||
|
||||
constructor(settingsStore) {
|
||||
makeAutoObservable(this);
|
||||
@ -66,6 +67,7 @@ class SelectedFolderStore {
|
||||
this.logo = null;
|
||||
this.tags = null;
|
||||
this.rootFolderId = null;
|
||||
this.security = null;
|
||||
};
|
||||
|
||||
setParentId = (parentId) => {
|
||||
|
@ -194,41 +194,12 @@ class SettingsStore {
|
||||
this.hideConfirmConvertSave = hideConfirmConvertSave;
|
||||
};
|
||||
|
||||
canWebEdit = (extension) => presentInArray(this.extsWebEdited, extension);
|
||||
|
||||
canViewedDocs = (extension) =>
|
||||
presentInArray(this.extsWebPreviewed, extension);
|
||||
|
||||
canConvert = (extension) => presentInArray(this.extsMustConvert, extension);
|
||||
|
||||
canWebComment = (extension) =>
|
||||
presentInArray(this.extsWebCommented, extension);
|
||||
|
||||
canWebReview = (extension) => presentInArray(this.extsWebReviewed, extension);
|
||||
|
||||
canFormFillingDocs = (extension) =>
|
||||
presentInArray(this.extsWebRestrictedEditing, extension);
|
||||
|
||||
canWebFilterEditing = (extension) =>
|
||||
presentInArray(this.extsWebCustomFilterEditing, extension);
|
||||
|
||||
isMediaOrImage = (fileExst) => {
|
||||
if (
|
||||
this.extsVideo.includes(fileExst) ||
|
||||
this.extsImage.includes(fileExst) ||
|
||||
this.extsAudio.includes(fileExst)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
isArchive = (extension) => presentInArray(this.extsArchive, extension);
|
||||
|
||||
isImage = (extension) => presentInArray(this.extsImage, extension);
|
||||
|
||||
isVideo = (extension) => presentInArray(this.extsVideo, extension);
|
||||
|
||||
isSound = (extension) => presentInArray(this.extsAudio, extension);
|
||||
|
||||
isHtml = (extension) => presentInArray(this.html, extension);
|
||||
|
@ -901,7 +901,7 @@ class UploadDataStore {
|
||||
path
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch((error) => {
|
||||
if (this.files[indexOfFile] === undefined) {
|
||||
this.primaryProgressDataStore.setPrimaryProgressBarData({
|
||||
icon: "upload",
|
||||
@ -911,8 +911,18 @@ class UploadDataStore {
|
||||
});
|
||||
return Promise.resolve();
|
||||
}
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
this.files[indexOfFile].error = err;
|
||||
this.files[indexOfFile].error = errorMessage;
|
||||
|
||||
//dispatch(setUploadData(uploadData));
|
||||
|
||||
|
@ -6,7 +6,8 @@ import { FileStatus } from "@docspace/common/constants";
|
||||
class VersionHistoryStore {
|
||||
isVisible = false;
|
||||
fileId = null;
|
||||
fileAccess = null;
|
||||
|
||||
fileSecurity = null;
|
||||
versions = null;
|
||||
filesStore = null;
|
||||
showProgressBar = false;
|
||||
@ -62,8 +63,9 @@ class VersionHistoryStore {
|
||||
setVerHistoryFileId = (fileId) => {
|
||||
this.fileId = fileId;
|
||||
};
|
||||
setVerHistoryFileAccess = (access) => {
|
||||
this.fileAccess = access;
|
||||
|
||||
setVerHistoryFileSecurity = (security) => {
|
||||
this.fileSecurity = security;
|
||||
};
|
||||
setVersions = (versions) => {
|
||||
this.versions = versions;
|
||||
@ -96,7 +98,7 @@ class VersionHistoryStore {
|
||||
fetchFileVersions = (fileId, access) => {
|
||||
if (this.fileId !== fileId || !this.versions) {
|
||||
this.setVerHistoryFileId(fileId);
|
||||
this.setVerHistoryFileAccess(access);
|
||||
this.setVerHistoryFileSecurity(access);
|
||||
|
||||
return api.files
|
||||
.getFileVersionInfo(fileId)
|
||||
|
@ -1,143 +1,9 @@
|
||||
import { ShareAccessRights } from "../../constants/index";
|
||||
|
||||
import {
|
||||
RoomsActions,
|
||||
OwnerRoomsActions,
|
||||
RoomAdminRoomsActions,
|
||||
EditorRoomsActions,
|
||||
FormFillerRoomsActions,
|
||||
ReviewerRoomsActions,
|
||||
CommentatorRoomsActions,
|
||||
ViewerRoomsActions,
|
||||
} from "./Rooms";
|
||||
|
||||
import {
|
||||
ArchiveRoomsActions,
|
||||
OwnerArchiveRoomsActions,
|
||||
RoomAdminArchiveRoomsActions,
|
||||
EditorArchiveRoomsActions,
|
||||
FormFillerArchiveRoomsActions,
|
||||
ReviewerArchiveRoomsActions,
|
||||
CommentatorArchiveRoomsActions,
|
||||
ViewerArchiveRoomsActions,
|
||||
} from "./ArchiveRoom";
|
||||
|
||||
import {
|
||||
FilesActions,
|
||||
OwnerFilesActions,
|
||||
RoomAdminFilesActions,
|
||||
EditorFilesActions,
|
||||
FormFillerFilesActions,
|
||||
ReviewerFilesActions,
|
||||
CommentatorFilesActions,
|
||||
ViewerFilesActions,
|
||||
} from "./Files";
|
||||
|
||||
import {
|
||||
ArchiveFilesActions,
|
||||
OwnerArchiveFilesActions,
|
||||
RoomAdminArchiveFilesActions,
|
||||
EditorArchiveFilesActions,
|
||||
FormFillerArchiveFilesActions,
|
||||
ReviewerArchiveFilesActions,
|
||||
CommentatorArchiveFilesActions,
|
||||
ViewerArchiveFilesActions,
|
||||
} from "./ArchiveFiles";
|
||||
|
||||
import {
|
||||
OwnerAccountsActions,
|
||||
DocSpaceAdminAccountsActions,
|
||||
RoomAdminAccountsActions,
|
||||
} from "./Accounts";
|
||||
|
||||
export const getRoomRoleActions = (access) => {
|
||||
switch (access) {
|
||||
case ShareAccessRights.None:
|
||||
case ShareAccessRights.FullAccess:
|
||||
return OwnerRoomsActions;
|
||||
case ShareAccessRights.RoomManager:
|
||||
return RoomAdminRoomsActions;
|
||||
case ShareAccessRights.Editing:
|
||||
return EditorRoomsActions;
|
||||
case ShareAccessRights.FormFilling:
|
||||
return FormFillerRoomsActions;
|
||||
case ShareAccessRights.Review:
|
||||
return ReviewerRoomsActions;
|
||||
case ShareAccessRights.Comment:
|
||||
return CommentatorRoomsActions;
|
||||
case ShareAccessRights.ReadOnly:
|
||||
return ViewerRoomsActions;
|
||||
default:
|
||||
return RoomsActions;
|
||||
}
|
||||
};
|
||||
|
||||
export const getFileRoleActions = (access) => {
|
||||
switch (access) {
|
||||
case ShareAccessRights.None:
|
||||
case ShareAccessRights.FullAccess:
|
||||
return OwnerFilesActions;
|
||||
case ShareAccessRights.RoomManager:
|
||||
return RoomAdminFilesActions;
|
||||
case ShareAccessRights.Editing:
|
||||
return EditorFilesActions;
|
||||
case ShareAccessRights.FormFilling:
|
||||
return FormFillerFilesActions;
|
||||
case ShareAccessRights.Review:
|
||||
return ReviewerFilesActions;
|
||||
case ShareAccessRights.Comment:
|
||||
return CommentatorFilesActions;
|
||||
case ShareAccessRights.ReadOnly:
|
||||
return ViewerFilesActions;
|
||||
default:
|
||||
return FilesActions;
|
||||
}
|
||||
};
|
||||
|
||||
export const getArchiveRoomRoleActions = (access) => {
|
||||
switch (access) {
|
||||
case ShareAccessRights.None:
|
||||
case ShareAccessRights.FullAccess:
|
||||
return OwnerArchiveRoomsActions;
|
||||
case ShareAccessRights.RoomManager:
|
||||
return RoomAdminArchiveRoomsActions;
|
||||
case ShareAccessRights.Editing:
|
||||
return EditorArchiveRoomsActions;
|
||||
case ShareAccessRights.FormFilling:
|
||||
return FormFillerArchiveRoomsActions;
|
||||
case ShareAccessRights.Review:
|
||||
return ReviewerArchiveRoomsActions;
|
||||
case ShareAccessRights.Comment:
|
||||
return CommentatorArchiveRoomsActions;
|
||||
case ShareAccessRights.ReadOnly:
|
||||
return ViewerArchiveRoomsActions;
|
||||
default:
|
||||
return ArchiveRoomsActions;
|
||||
}
|
||||
};
|
||||
|
||||
export const getArchiveFileRoleActions = (access) => {
|
||||
switch (access) {
|
||||
case ShareAccessRights.None:
|
||||
case ShareAccessRights.FullAccess:
|
||||
return OwnerArchiveFilesActions;
|
||||
case ShareAccessRights.RoomManager:
|
||||
return RoomAdminArchiveFilesActions;
|
||||
case ShareAccessRights.Editing:
|
||||
return EditorArchiveFilesActions;
|
||||
case ShareAccessRights.FormFilling:
|
||||
return FormFillerArchiveFilesActions;
|
||||
case ShareAccessRights.Review:
|
||||
return ReviewerArchiveFilesActions;
|
||||
case ShareAccessRights.Comment:
|
||||
return CommentatorArchiveFilesActions;
|
||||
case ShareAccessRights.ReadOnly:
|
||||
return ViewerArchiveFilesActions;
|
||||
default:
|
||||
return ArchiveFilesActions;
|
||||
}
|
||||
};
|
||||
|
||||
export const getAccountsTypeActions = (isAdmin, isOwner) => {
|
||||
if (isOwner) return OwnerAccountsActions;
|
||||
|
||||
|
@ -16,7 +16,7 @@ class AxiosClient {
|
||||
|
||||
if (apiOrigin !== "") {
|
||||
headers = {
|
||||
'Access-Control-Allow-Credentials' : true
|
||||
"Access-Control-Allow-Credentials": true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ class AxiosClient {
|
||||
baseURL: apiBaseURL,
|
||||
responseType: "json",
|
||||
timeout: apiTimeout, // default is `0` (no timeout)
|
||||
withCredentials: true
|
||||
withCredentials: true,
|
||||
};
|
||||
|
||||
if (headers) {
|
||||
@ -106,11 +106,11 @@ class AxiosClient {
|
||||
};
|
||||
|
||||
const onError = (error) => {
|
||||
//console.error("Request Failed:", error);
|
||||
console.log("Request Failed:", { error });
|
||||
|
||||
let errorText = error.response
|
||||
? this.getResponseError(error.response)
|
||||
: error.message;
|
||||
// let errorText = error.response
|
||||
// ? this.getResponseError(error.response)
|
||||
// : error.message;
|
||||
|
||||
if (error?.response?.status === 401 && this.isSSR) errorText = 401;
|
||||
|
||||
@ -138,7 +138,7 @@ class AxiosClient {
|
||||
break;
|
||||
}
|
||||
|
||||
return Promise.reject(errorText || error);
|
||||
return Promise.reject(error);
|
||||
} else {
|
||||
switch (error.response?.status) {
|
||||
case 401:
|
||||
|
@ -61,19 +61,19 @@ const RowContent = (props) => {
|
||||
onClick={onClick}
|
||||
style={style}
|
||||
widthProp={sectionWidth}
|
||||
isMobile={isMobile}
|
||||
isMobile={true}
|
||||
>
|
||||
<MainContainerWrapper
|
||||
disableSideInfo={disableSideInfo}
|
||||
mainContainerWidth={mainContainerWidth}
|
||||
widthProp={sectionWidth}
|
||||
isMobile={isMobile}
|
||||
isMobile={true}
|
||||
className="row-main-container-wrapper"
|
||||
>
|
||||
<MainContainer
|
||||
className="rowMainContainer"
|
||||
widthProp={sectionWidth}
|
||||
isMobile={isMobile}
|
||||
isMobile={true}
|
||||
>
|
||||
{children[0]}
|
||||
</MainContainer>
|
||||
@ -90,7 +90,7 @@ const RowContent = (props) => {
|
||||
element.props && element.props.containerMinWidth
|
||||
}
|
||||
widthProp={sectionWidth}
|
||||
isMobile={isMobile}
|
||||
isMobile={true}
|
||||
>
|
||||
{element}
|
||||
</SideContainerWrapper>
|
||||
@ -102,7 +102,7 @@ const RowContent = (props) => {
|
||||
className="row-content_tablet-side-info"
|
||||
color={sideColor}
|
||||
widthProp={sectionWidth}
|
||||
isMobile={isMobile}
|
||||
isMobile={true}
|
||||
convertSideInfo={convertSideInfo}
|
||||
>
|
||||
{sideInfo}
|
||||
@ -127,7 +127,6 @@ RowContent.propTypes = {
|
||||
/** Accepts css style */
|
||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||
sectionWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
isMobile: PropTypes.bool,
|
||||
convertSideInfo: PropTypes.bool,
|
||||
};
|
||||
|
||||
|
@ -49,7 +49,7 @@ const StyledRowContent = styled.div`
|
||||
${(props) =>
|
||||
(!props.disableSideInfo &&
|
||||
props.widthProp &&
|
||||
props.widthProp < size.tablet) ||
|
||||
props.widthProp <= size.tablet) ||
|
||||
props.isMobile
|
||||
? `${containerTabletStyle}`
|
||||
: `
|
||||
@ -75,7 +75,7 @@ const MainContainerWrapper = styled.div`
|
||||
${(props) =>
|
||||
(!props.disableSideInfo &&
|
||||
props.widthProp &&
|
||||
props.widthProp < size.tablet) ||
|
||||
props.widthProp <= size.tablet) ||
|
||||
props.isMobile
|
||||
? css`
|
||||
${mainWrapperTabletStyle}
|
||||
@ -95,7 +95,7 @@ const MainContainer = styled.div`
|
||||
max-width: 100%;
|
||||
|
||||
${(props) =>
|
||||
(props.widthProp && props.widthProp < size.tablet) || props.isMobile
|
||||
(props.widthProp && props.widthProp <= size.tablet) || props.isMobile
|
||||
? `${mainContainerTabletStyle}`
|
||||
: `
|
||||
@media ${tablet} {
|
||||
@ -116,7 +116,7 @@ const SideContainerWrapper = styled.div`
|
||||
${commonCss};
|
||||
|
||||
${(props) =>
|
||||
(props.widthProp && props.widthProp < size.tablet) || props.isMobile
|
||||
(props.widthProp && props.widthProp <= size.tablet) || props.isMobile
|
||||
? `${truncateCss}`
|
||||
: `
|
||||
@media ${tablet} {
|
||||
@ -139,7 +139,7 @@ const SideContainerWrapper = styled.div`
|
||||
${(props) =>
|
||||
(!props.disableSideInfo &&
|
||||
props.widthProp &&
|
||||
props.widthProp < size.tablet) ||
|
||||
props.widthProp <= size.tablet) ||
|
||||
props.isMobile
|
||||
? `display: none;`
|
||||
: `
|
||||
@ -154,7 +154,7 @@ const TabletSideInfo = styled.div`
|
||||
display: none;
|
||||
${(props) => (props.color ? `color: ${props.color};` : null)}
|
||||
${(props) =>
|
||||
(props.widthProp && props.widthProp < size.tablet) || props.isMobile
|
||||
(props.widthProp && props.widthProp <= size.tablet) || props.isMobile
|
||||
? `${sideInfoTabletStyle}`
|
||||
: `
|
||||
@media ${tablet} {
|
||||
|
@ -140,15 +140,28 @@ function fatal(data, title, timeout, withCross, centerPosition) {
|
||||
}
|
||||
|
||||
function error(data, title, timeout, withCross, centerPosition) {
|
||||
console.log("toast error: ", { data });
|
||||
const dataType = typeof data;
|
||||
const message =
|
||||
dataType === "string"
|
||||
? data
|
||||
: dataType === "object" && data.statusText
|
||||
? data.statusText
|
||||
: dataType === "object" && data.message
|
||||
? data.message
|
||||
: "";
|
||||
let message = "";
|
||||
|
||||
if (dataType === "string") {
|
||||
message = data;
|
||||
} else if (dataType === "object") {
|
||||
message =
|
||||
data?.response?.data?.error?.message ||
|
||||
data?.statusText ||
|
||||
data?.message ||
|
||||
"";
|
||||
}
|
||||
|
||||
// const message =
|
||||
// dataType === "string"
|
||||
// ? data
|
||||
// : dataType === "object" && data.statusText
|
||||
// ? data.statusText
|
||||
// : dataType === "object" && data.message
|
||||
// ? data.message
|
||||
// : "";
|
||||
|
||||
return notify(
|
||||
"error",
|
||||
|
@ -22,14 +22,9 @@ import {
|
||||
import { EditorWrapper } from "../components/StyledEditor";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import withDialogs from "../helpers/withDialogs";
|
||||
import { canConvert } from "../helpers/utils";
|
||||
import { assign } from "@docspace/common/utils";
|
||||
import toastr from "@docspace/components/toast/toastr";
|
||||
import { DocumentEditor } from "@onlyoffice/document-editor-react";
|
||||
import {
|
||||
getArchiveFileRoleActions,
|
||||
getFileRoleActions,
|
||||
} from "@docspace/common/utils/actions";
|
||||
|
||||
toast.configure();
|
||||
|
||||
@ -103,9 +98,7 @@ function Editor({
|
||||
const { t } = useTranslation(["Editor", "Common"]);
|
||||
|
||||
if (fileInfo) {
|
||||
userAccessRights = isArchiveFolderRoot
|
||||
? getArchiveFileRoleActions(fileInfo.access)
|
||||
: getFileRoleActions(fileInfo.access);
|
||||
userAccessRights = fileInfo.security;
|
||||
}
|
||||
useEffect(() => {
|
||||
if (error && mfReady) {
|
||||
@ -131,9 +124,9 @@ function Editor({
|
||||
if (
|
||||
!view &&
|
||||
fileInfo &&
|
||||
fileInfo.canWebRestrictedEditing &&
|
||||
fileInfo.canFillForms &&
|
||||
!fileInfo.canEdit
|
||||
fileInfo.viewAccessability.WebRestrictedEditing &&
|
||||
fileInfo.security.FillForms &&
|
||||
!fileInfo.security.Edit
|
||||
) {
|
||||
try {
|
||||
initForm();
|
||||
@ -166,7 +159,7 @@ function Editor({
|
||||
url.indexOf("#message/") > -1 &&
|
||||
fileInfo &&
|
||||
fileInfo?.fileExst &&
|
||||
canConvert(fileInfo.fileExst, filesSettings)
|
||||
fileInfo?.viewAccessability?.Convert
|
||||
) {
|
||||
showDocEditorMessage(url);
|
||||
}
|
||||
@ -228,7 +221,7 @@ function Editor({
|
||||
if (index) {
|
||||
let convertUrl = url.substring(0, index);
|
||||
|
||||
if (canConvert(fileInfo.fileExst, filesSettings)) {
|
||||
if (fileInfo?.viewAccessability?.Convert) {
|
||||
const newUrl = await convertDocumentUrl();
|
||||
if (newUrl) {
|
||||
convertUrl = newUrl.webUrl;
|
||||
@ -279,9 +272,20 @@ function Editor({
|
||||
),
|
||||
history: getDocumentHistory(updateVersions, historyLength),
|
||||
});
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
docEditor.refreshHistory({
|
||||
error: `${e}`, //TODO: maybe need to display something else.
|
||||
error: `${errorMessage}`, //TODO: maybe need to display something else.
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -330,9 +334,19 @@ function Editor({
|
||||
currentVersion: getCurrentDocumentVersion(fileHistory, historyLength),
|
||||
history: getDocumentHistory(fileHistory, historyLength),
|
||||
});
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
docEditor.refreshHistory({
|
||||
error: `${e}`, //TODO: maybe need to display something else.
|
||||
error: `${errorMessage}`, //TODO: maybe need to display something else.
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -361,9 +375,20 @@ function Editor({
|
||||
url: versionDifference.url,
|
||||
version,
|
||||
});
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
docEditor.setHistoryData({
|
||||
error: `${e}`, //TODO: maybe need to display something else.
|
||||
error: `${errorMessage}`, //TODO: maybe need to display something else.
|
||||
version,
|
||||
});
|
||||
}
|
||||
@ -551,11 +576,11 @@ function Editor({
|
||||
// onRequestSharingSettings = onSDKRequestSharingSettings;
|
||||
// }
|
||||
|
||||
if (userAccessRights.rename) {
|
||||
if (userAccessRights.Rename) {
|
||||
onRequestRename = onSDKRequestRename;
|
||||
}
|
||||
|
||||
if (userAccessRights.viewVersionHistory) {
|
||||
if (userAccessRights.ReadHistory) {
|
||||
onRequestHistory = onSDKRequestHistory;
|
||||
}
|
||||
|
||||
@ -569,7 +594,7 @@ function Editor({
|
||||
onRequestCompareFile = onSDKRequestCompareFile;
|
||||
}
|
||||
|
||||
if (userAccessRights.changeVersionHistory) {
|
||||
if (userAccessRights.EditHistory) {
|
||||
onRequestRestore = onSDKRequestRestore;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,5 @@
|
||||
import pkg from "../../../package.json";
|
||||
|
||||
export const canConvert = (extension, filesSettings) => {
|
||||
const array = filesSettings?.extsMustConvert || [];
|
||||
const result = array.findIndex((item) => item === extension);
|
||||
return result === -1 ? false : true;
|
||||
};
|
||||
|
||||
export const initI18n = (initialI18nStoreASC) => {
|
||||
if (!initialI18nStoreASC || window.i18n) return;
|
||||
|
||||
|
@ -164,9 +164,20 @@ const LoginForm: React.FC<ILoginFormProps> = ({
|
||||
else window.location.replace("/"); //TODO: save { user, hash } for tfa
|
||||
})
|
||||
.catch((error) => {
|
||||
let errorMessage = "";
|
||||
if (typeof error === "object") {
|
||||
errorMessage =
|
||||
error?.response?.data?.error?.message ||
|
||||
error?.statusText ||
|
||||
error?.message ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error;
|
||||
}
|
||||
|
||||
setIsEmailErrorShow(true);
|
||||
setErrorText(error);
|
||||
setPasswordValid(!error);
|
||||
setErrorText(errorMessage);
|
||||
setPasswordValid(!errorMessage);
|
||||
setIsLoading(false);
|
||||
focusInput();
|
||||
});
|
||||
|
@ -44,10 +44,10 @@ public class FileDto<T> : FileEntryDto<T>
|
||||
public Thumbnail ThumbnailStatus { get; set; }
|
||||
public bool? Locked { get; set; }
|
||||
public string LockedBy { get; set; }
|
||||
public bool CanWebRestrictedEditing { get; set; }
|
||||
public bool CanFillForms { get; set; }
|
||||
public bool DenyDownload { get; set; }
|
||||
public bool DenySharing { get; set; }
|
||||
public IDictionary<Accessability, bool> ViewAccessability { get; set; }
|
||||
|
||||
protected internal override FileEntryType EntryType { get => FileEntryType.File; }
|
||||
|
||||
public FileDto() { }
|
||||
@ -138,6 +138,8 @@ public class FileDtoHelper : FileEntryDtoHelper
|
||||
}
|
||||
}
|
||||
|
||||
result.ViewAccessability = _fileUtility.GetAccessability(file.Title);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -156,8 +158,6 @@ public class FileDtoHelper : FileEntryDtoHelper
|
||||
result.Encrypted = file.Encrypted.NullIfDefault();
|
||||
result.Locked = file.Locked.NullIfDefault();
|
||||
result.LockedBy = file.LockedBy;
|
||||
result.CanWebRestrictedEditing = _fileUtility.CanWebRestrictedEditing(file.Title);
|
||||
result.CanFillForms = await _fileSecurity.CanFillFormsAsync(file);
|
||||
result.DenyDownload = file.DenyDownload;
|
||||
result.DenySharing = file.DenySharing;
|
||||
result.Access = file.Access;
|
||||
|
@ -24,6 +24,8 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using static ASC.Files.Core.Security.FileSecurity;
|
||||
|
||||
namespace ASC.Files.Core.ApiModels.ResponseDto;
|
||||
|
||||
public abstract class FileEntryDto
|
||||
@ -67,7 +69,7 @@ public abstract class FileEntryDto<T> : FileEntryDto
|
||||
public T Id { get; set; }
|
||||
public T RootFolderId { get; set; }
|
||||
public bool CanShare { get; set; }
|
||||
public bool CanEdit { get; set; }
|
||||
public IDictionary<FilesSecurityActions, bool> Security { get; set; }
|
||||
|
||||
protected FileEntryDto(FileEntry<T> entry)
|
||||
: base(entry)
|
||||
@ -82,6 +84,8 @@ public abstract class FileEntryDto<T> : FileEntryDto
|
||||
[Scope]
|
||||
public class FileEntryDtoHelper
|
||||
{
|
||||
|
||||
|
||||
private readonly ApiDateTimeHelper _apiDateTimeHelper;
|
||||
private readonly EmployeeDtoHelper _employeeWraperHelper;
|
||||
private readonly FileSharingHelper _fileSharingHelper;
|
||||
@ -90,7 +94,8 @@ public class FileEntryDtoHelper
|
||||
public FileEntryDtoHelper(
|
||||
ApiDateTimeHelper apiDateTimeHelper,
|
||||
EmployeeDtoHelper employeeWraperHelper,
|
||||
FileSharingHelper fileSharingHelper, FileSecurity fileSecurity
|
||||
FileSharingHelper fileSharingHelper,
|
||||
FileSecurity fileSecurity
|
||||
)
|
||||
{
|
||||
_apiDateTimeHelper = apiDateTimeHelper;
|
||||
@ -101,6 +106,11 @@ public class FileEntryDtoHelper
|
||||
|
||||
protected internal async Task<T> GetAsync<T, TId>(FileEntry<TId> entry) where T : FileEntryDto<TId>, new()
|
||||
{
|
||||
if (entry.Security == null)
|
||||
{
|
||||
entry = await _fileSecurity.SetSecurity(new[] { entry }.ToAsyncEnumerable()).FirstAsync();
|
||||
}
|
||||
|
||||
return new T
|
||||
{
|
||||
Id = entry.Id,
|
||||
@ -117,7 +127,7 @@ public class FileEntryDtoHelper
|
||||
ProviderKey = entry.ProviderKey,
|
||||
ProviderId = entry.ProviderId.NullIfDefault(),
|
||||
CanShare = await _fileSharingHelper.CanSetAccessAsync(entry),
|
||||
CanEdit = await _fileSecurity.CanEditAsync(entry)
|
||||
Security = entry.Security
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ public class FileShareDto
|
||||
public object SharedTo { get; set; }
|
||||
public bool IsLocked { get; set; }
|
||||
public bool IsOwner { get; set; }
|
||||
public bool CanEditAccess { get; set; }
|
||||
|
||||
public static FileShareDto GetSample()
|
||||
{
|
||||
@ -77,7 +78,8 @@ public class FileShareDtoHelper
|
||||
var result = new FileShareDto
|
||||
{
|
||||
IsOwner = aceWrapper.Owner,
|
||||
IsLocked = aceWrapper.LockedRights
|
||||
IsLocked = aceWrapper.LockedRights,
|
||||
CanEditAccess = aceWrapper.CanEditAccess,
|
||||
};
|
||||
|
||||
if (aceWrapper.SubjectGroup)
|
||||
|
@ -24,6 +24,8 @@
|
||||
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
using static ASC.Files.Core.Security.FileSecurity;
|
||||
|
||||
namespace ASC.Files.Core;
|
||||
|
||||
[Serializable]
|
||||
@ -110,11 +112,15 @@ public abstract class FileEntry<T> : FileEntry, ICloneable, IFileEntry<T>
|
||||
{
|
||||
public T Id { get; set; }
|
||||
public T ParentId { get; set; }
|
||||
|
||||
public IDictionary<FilesSecurityActions, bool> Security { get; set; }
|
||||
|
||||
private T _folderIdDisplay;
|
||||
private readonly GlobalFolderHelper _globalFolderHelper;
|
||||
private readonly FilesSettingsHelper _filesSettingsHelper;
|
||||
private readonly FileDateTime _fileDateTime;
|
||||
|
||||
|
||||
protected FileEntry() { }
|
||||
|
||||
protected FileEntry(
|
||||
|
@ -349,14 +349,16 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
var prevVisible = breadCrumbs.ElementAtOrDefault(breadCrumbs.Count - 2);
|
||||
if (prevVisible != null && !DocSpaceHelper.IsRoom(parent.FolderType))
|
||||
{
|
||||
if (prevVisible is Folder<string> f1)
|
||||
if (prevVisible.FileEntryType == FileEntryType.Folder)
|
||||
{
|
||||
parent.ParentId = (T)Convert.ChangeType(f1.Id, typeof(T));
|
||||
}
|
||||
|
||||
if (prevVisible is Folder<int> f2)
|
||||
{
|
||||
parent.ParentId = (T)Convert.ChangeType(f2.Id, typeof(T));
|
||||
if (prevVisible is Folder<string> f1)
|
||||
{
|
||||
parent.ParentId = (T)Convert.ChangeType(f1.Id, typeof(T));
|
||||
}
|
||||
else if (prevVisible is Folder<int> f2)
|
||||
{
|
||||
parent.ParentId = (T)Convert.ChangeType(f2.Id, typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,9 +366,20 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
|| parent.FolderType == FolderType.SHARE
|
||||
|| parent.RootFolderType == FolderType.Privacy;
|
||||
|
||||
entries = entries.Where(x => x.FileEntryType == FileEntryType.Folder ||
|
||||
x is File<string> f1 && !_fileConverter.IsConverting(f1) ||
|
||||
x is File<int> f2 && !_fileConverter.IsConverting(f2));
|
||||
entries = entries.Where(x =>
|
||||
{
|
||||
if (x.FileEntryType == FileEntryType.Folder)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x is File<string> f1)
|
||||
{
|
||||
return !_fileConverter.IsConverting(f1);
|
||||
}
|
||||
|
||||
return x is File<int> f2 && !_fileConverter.IsConverting(f2);
|
||||
});
|
||||
|
||||
var result = new DataWrapper<T>
|
||||
{
|
||||
@ -374,14 +387,17 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
Entries = entries.ToList(),
|
||||
FolderPathParts = new List<object>(breadCrumbs.Select(f =>
|
||||
{
|
||||
if (f is Folder<string> f1)
|
||||
if (f.FileEntryType == FileEntryType.Folder)
|
||||
{
|
||||
return (object)f1.Id;
|
||||
}
|
||||
if (f is Folder<string> f1)
|
||||
{
|
||||
return (object)f1.Id;
|
||||
}
|
||||
|
||||
if (f is Folder<int> f2)
|
||||
{
|
||||
return f2.Id;
|
||||
if (f is Folder<int> f2)
|
||||
{
|
||||
return f2.Id;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -393,17 +409,6 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<object> GetFolderItemsXmlAsync(T parentId, int from, int count, FilterType filter, bool subjectGroup, string subjectID, string search, bool searchInContent, bool withSubfolders, OrderBy orderBy)
|
||||
{
|
||||
var folderItems = await GetFolderItemsAsync(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy);
|
||||
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StreamContent(_serializer.ToXml(folderItems))
|
||||
};
|
||||
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
|
||||
return response;
|
||||
}
|
||||
|
||||
public async Task<List<FileEntry>> GetItemsAsync<TId>(IEnumerable<TId> filesId, IEnumerable<TId> foldersId, FilterType filter, bool subjectGroup, string subjectID, string search)
|
||||
{
|
||||
var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID);
|
||||
@ -1312,7 +1317,7 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
}
|
||||
|
||||
ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
|
||||
ErrorIf(!readLink && !await _fileSecurity.CanReadAsync(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
|
||||
ErrorIf(!readLink && !await _fileSecurity.CanReadHistoryAsync(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
|
||||
ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest);
|
||||
|
||||
await foreach (var f in fileDao.GetEditHistoryAsync(_documentServiceHelper, file.Id))
|
||||
@ -1340,7 +1345,7 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
}
|
||||
|
||||
ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
|
||||
ErrorIf(!readLink && !await _fileSecurity.CanReadAsync(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
|
||||
ErrorIf(!readLink && !await _fileSecurity.CanReadHistoryAsync(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
|
||||
ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest);
|
||||
|
||||
var result = new EditHistoryDataDto
|
||||
@ -2696,7 +2701,7 @@ public class FileStorageService<T> //: IFileStorageService
|
||||
var room = await folderDao.GetFolderAsync(folderId);
|
||||
|
||||
ErrorIf(room == null, FilesCommonResource.ErrorMassage_FolderNotFound);
|
||||
ErrorIf(!await _fileSecurity.CanReadAsync(room), FilesCommonResource.ErrorMassage_SecurityException_ReadFolder);
|
||||
ErrorIf(!await _fileSecurity.CanPinAsync(room), FilesCommonResource.ErrorrMessage_PinRoom);
|
||||
|
||||
var tagDao = GetTagDao();
|
||||
var tag = Tag.Pin(_authContext.CurrentAccount.ID, room);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -119,12 +119,12 @@ public class RoomLogoManager
|
||||
return room;
|
||||
}
|
||||
|
||||
public async Task<Folder<T>> DeleteAsync<T>(T id)
|
||||
public async Task<Folder<T>> DeleteAsync<T>(T id, bool checkPermissions = true)
|
||||
{
|
||||
var folderDao = _daoFactory.GetFolderDao<T>();
|
||||
var room = await folderDao.GetFolderAsync(id);
|
||||
|
||||
if (!await _fileSecurity.CanEditRoomAsync(room))
|
||||
if (checkPermissions && !await _fileSecurity.CanEditRoomAsync(room))
|
||||
{
|
||||
throw new InvalidOperationException("You don't have permission to edit the room");
|
||||
}
|
||||
|
@ -174,6 +174,20 @@ public class FileUtilityConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
public enum Accessability
|
||||
{
|
||||
ImageView,
|
||||
MediaView,
|
||||
WebView,
|
||||
WebEdit,
|
||||
WebReview,
|
||||
WebCustomFilterEditing,
|
||||
WebRestrictedEditing,
|
||||
WebComment,
|
||||
CoAuhtoring,
|
||||
Convert
|
||||
}
|
||||
|
||||
[Scope]
|
||||
public class FileUtility
|
||||
{
|
||||
@ -296,6 +310,54 @@ public class FileUtility
|
||||
return FileType.Unknown;
|
||||
}
|
||||
|
||||
public IDictionary<Accessability, bool> GetAccessability(string fileName)
|
||||
{
|
||||
var result = new Dictionary<Accessability, bool>();
|
||||
|
||||
foreach (var r in Enum.GetValues<Accessability>())
|
||||
{
|
||||
var val = false;
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case Accessability.ImageView:
|
||||
val = CanImageView(fileName);
|
||||
break;
|
||||
case Accessability.MediaView:
|
||||
val = CanMediaView(fileName);
|
||||
break;
|
||||
case Accessability.WebView:
|
||||
val = CanWebView(fileName);
|
||||
break;
|
||||
case Accessability.WebEdit:
|
||||
val = CanWebEdit(fileName);
|
||||
break;
|
||||
case Accessability.WebReview:
|
||||
val = CanWebReview(fileName);
|
||||
break;
|
||||
case Accessability.WebCustomFilterEditing:
|
||||
val = CanWebCustomFilterEditing(fileName);
|
||||
break;
|
||||
case Accessability.WebRestrictedEditing:
|
||||
val = CanWebRestrictedEditing(fileName);
|
||||
break;
|
||||
case Accessability.WebComment:
|
||||
val = CanWebComment(fileName);
|
||||
break;
|
||||
case Accessability.CoAuhtoring:
|
||||
val = CanCoAuhtoring(fileName);
|
||||
break;
|
||||
case Accessability.Convert:
|
||||
val = CanConvert(fileName);
|
||||
break;
|
||||
}
|
||||
|
||||
result.Add(r, val);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool CanImageView(string fileName)
|
||||
{
|
||||
var ext = GetFileExtension(fileName);
|
||||
@ -350,6 +412,13 @@ public class FileUtility
|
||||
return ExtsCoAuthoring.Exists(r => r.Equals(ext, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
|
||||
public bool CanConvert(string fileName)
|
||||
{
|
||||
var ext = GetFileExtension(fileName);
|
||||
return ExtsMustConvert.Exists(r => r.Equals(ext, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
public bool CanIndex(string fileName)
|
||||
{
|
||||
var ext = GetFileExtension(fileName);
|
||||
|
@ -564,6 +564,24 @@ namespace ASC.Files.Core.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You don't have enough permission to copy the file.
|
||||
/// </summary>
|
||||
public static string ErrorMassage_SecurityException_CopyFile {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorMassage_SecurityException_CopyFile", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You don't have enough permission to copy the folder.
|
||||
/// </summary>
|
||||
public static string ErrorMassage_SecurityException_CopyFolder {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorMassage_SecurityException_CopyFolder", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You don't have enough permission to create.
|
||||
/// </summary>
|
||||
@ -753,6 +771,24 @@ namespace ASC.Files.Core.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You don't have permission to copy to this folder.
|
||||
/// </summary>
|
||||
public static string ErrorMessage_SecurityException_CopyToFolder {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorMessage_SecurityException_CopyToFolder", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You don't have permission to move to this folder.
|
||||
/// </summary>
|
||||
public static string ErrorMessage_SecurityException_MoveToFolder {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorMessage_SecurityException_MoveToFolder", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You don't have enough permission to archive the room.
|
||||
/// </summary>
|
||||
@ -771,6 +807,15 @@ namespace ASC.Files.Core.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to You can't pin a room.
|
||||
/// </summary>
|
||||
public static string ErrorrMessage_PinRoom {
|
||||
get {
|
||||
return ResourceManager.GetString("ErrorrMessage_PinRoom", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Everyone.
|
||||
/// </summary>
|
||||
|
@ -285,6 +285,12 @@
|
||||
<data name="ErrorMassage_SecurityException_Auth" xml:space="preserve">
|
||||
<value>Can't authorize at {0} provider with given credentials.</value>
|
||||
</data>
|
||||
<data name="ErrorMassage_SecurityException_CopyFile" xml:space="preserve">
|
||||
<value>You don't have enough permission to copy the file</value>
|
||||
</data>
|
||||
<data name="ErrorMassage_SecurityException_CopyFolder" xml:space="preserve">
|
||||
<value>You don't have enough permission to copy the folder</value>
|
||||
</data>
|
||||
<data name="ErrorMassage_SecurityException_Create" xml:space="preserve">
|
||||
<value>You don't have enough permission to create</value>
|
||||
</data>
|
||||
@ -348,12 +354,21 @@
|
||||
<data name="ErrorMessage_InvintationLink" xml:space="preserve">
|
||||
<value>The invitation link is invalid or it's validity has expired</value>
|
||||
</data>
|
||||
<data name="ErrorMessage_SecurityException_CopyToFolder" xml:space="preserve">
|
||||
<value>You don't have permission to copy to this folder</value>
|
||||
</data>
|
||||
<data name="ErrorMessage_SecurityException_MoveToFolder" xml:space="preserve">
|
||||
<value>You don't have permission to move to this folder</value>
|
||||
</data>
|
||||
<data name="ErrorMessage_UnarchiveRoom" xml:space="preserve">
|
||||
<value>You don't have enough permission to archive the room</value>
|
||||
</data>
|
||||
<data name="ErrorMessage_UpdateArchivedRoom" xml:space="preserve">
|
||||
<value>You cannot edit archived rooms</value>
|
||||
</data>
|
||||
<data name="ErrorrMessage_PinRoom" xml:space="preserve">
|
||||
<value>You can't pin a room</value>
|
||||
</data>
|
||||
<data name="Everyone" xml:space="preserve">
|
||||
<value>Everyone</value>
|
||||
</data>
|
||||
|
@ -106,7 +106,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteFoldersAsync(IEnumerable<T> folderIds, IServiceScope scope, bool isNeedSendActions = false)
|
||||
private async Task DeleteFoldersAsync(IEnumerable<T> folderIds, IServiceScope scope, bool isNeedSendActions = false, bool checkPermissions = true)
|
||||
{
|
||||
var scopeClass = scope.ServiceProvider.GetService<FileDeleteOperationScope>();
|
||||
var (fileMarker, filesMessageService, roomLogoManager) = scopeClass;
|
||||
@ -127,7 +127,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder;
|
||||
}
|
||||
else if (!_ignoreException && !await FilesSecurity.CanDeleteAsync(folder))
|
||||
else if (!_ignoreException && checkPermissions && !await FilesSecurity.CanDeleteAsync(folder))
|
||||
{
|
||||
canCalculate = FolderDao.CanCalculateSubitems(folderId) ? default : folderId;
|
||||
|
||||
@ -135,6 +135,8 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
}
|
||||
else
|
||||
{
|
||||
checkPermissions = isRoom ? false : checkPermissions;
|
||||
|
||||
canCalculate = FolderDao.CanCalculateSubitems(folderId) ? default : folderId;
|
||||
|
||||
await fileMarker.RemoveMarkAsNewForAllAsync(folder);
|
||||
@ -148,7 +150,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
|
||||
if (providerInfo.FolderId != null)
|
||||
{
|
||||
await roomLogoManager.DeleteAsync(providerInfo.FolderId);
|
||||
await roomLogoManager.DeleteAsync(providerInfo.FolderId, checkPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,16 +169,16 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
if (immediately && FolderDao.UseRecursiveOperation(folder.Id, default(T)))
|
||||
{
|
||||
var files = await FileDao.GetFilesAsync(folder.Id).ToListAsync();
|
||||
await DeleteFilesAsync(files, scope);
|
||||
await DeleteFilesAsync(files, scope, checkPermissions: checkPermissions);
|
||||
|
||||
var folders = await FolderDao.GetFoldersAsync(folder.Id).ToListAsync();
|
||||
await DeleteFoldersAsync(folders.Select(f => f.Id).ToList(), scope);
|
||||
await DeleteFoldersAsync(folders.Select(f => f.Id).ToList(), scope, checkPermissions: checkPermissions);
|
||||
|
||||
if (await FolderDao.IsEmptyAsync(folder.Id))
|
||||
{
|
||||
if (isRoom)
|
||||
{
|
||||
await roomLogoManager.DeleteAsync(folder.Id);
|
||||
await roomLogoManager.DeleteAsync(folder.Id, checkPermissions);
|
||||
}
|
||||
|
||||
await FolderDao.DeleteFolderAsync(folder.Id);
|
||||
@ -194,7 +196,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
else
|
||||
{
|
||||
var files = await FileDao.GetFilesAsync(folder.Id, new OrderBy(SortedByType.AZ, true), FilterType.FilesOnly, false, Guid.Empty, string.Empty, false, true).ToListAsync();
|
||||
var (isError, message) = await WithErrorAsync(scope, files, true);
|
||||
var (isError, message) = await WithErrorAsync(scope, files, true, checkPermissions);
|
||||
if (!_ignoreException && isError)
|
||||
{
|
||||
this[Err] = message;
|
||||
@ -205,7 +207,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
{
|
||||
if (isRoom)
|
||||
{
|
||||
await roomLogoManager.DeleteAsync(folder.Id);
|
||||
await roomLogoManager.DeleteAsync(folder.Id, checkPermissions);
|
||||
}
|
||||
|
||||
await FolderDao.DeleteFolderAsync(folder.Id);
|
||||
@ -238,7 +240,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteFilesAsync(IEnumerable<T> fileIds, IServiceScope scope, bool isNeedSendActions = false)
|
||||
private async Task DeleteFilesAsync(IEnumerable<T> fileIds, IServiceScope scope, bool isNeedSendActions = false, bool checkPermissions = true)
|
||||
{
|
||||
var scopeClass = scope.ServiceProvider.GetService<FileDeleteOperationScope>();
|
||||
var socketManager = scope.ServiceProvider.GetService<SocketManager>();
|
||||
@ -249,7 +251,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var file = await FileDao.GetFileAsync(fileId);
|
||||
var (isError, message) = await WithErrorAsync(scope, new[] { file }, false);
|
||||
var (isError, message) = await WithErrorAsync(scope, new[] { file }, false, checkPermissions);
|
||||
if (file == null)
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_FileNotFound;
|
||||
@ -316,7 +318,7 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<(bool isError, string message)> WithErrorAsync(IServiceScope scope, IEnumerable<File<T>> files, bool folder)
|
||||
private async Task<(bool isError, string message)> WithErrorAsync(IServiceScope scope, IEnumerable<File<T>> files, bool folder, bool checkPermissions)
|
||||
{
|
||||
var entryManager = scope.ServiceProvider.GetService<EntryManager>();
|
||||
var fileTracker = scope.ServiceProvider.GetService<FileTrackerHelper>();
|
||||
@ -324,13 +326,13 @@ class FileDeleteOperation<T> : FileOperation<FileDeleteOperationData<T>, T>
|
||||
string error = null;
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (!await FilesSecurity.CanDeleteAsync(file))
|
||||
if (checkPermissions && !await FilesSecurity.CanDeleteAsync(file))
|
||||
{
|
||||
error = FilesCommonResource.ErrorMassage_SecurityException_DeleteFile;
|
||||
|
||||
return (true, error);
|
||||
}
|
||||
if (await entryManager.FileLockedForMeAsync(file.Id))
|
||||
if (checkPermissions && await entryManager.FileLockedForMeAsync(file.Id))
|
||||
{
|
||||
error = FilesCommonResource.ErrorMassage_LockedFile;
|
||||
|
||||
|
@ -113,6 +113,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
{
|
||||
var fileMarker = scope.ServiceProvider.GetService<FileMarker>();
|
||||
var folderDao = scope.ServiceProvider.GetService<IFolderDao<TTo>>();
|
||||
var fileSecurity = scope.ServiceProvider.GetService<FileSecurity>();
|
||||
|
||||
this[Res] += string.Format("folder_{0}{1}", _daoFolderId, SplitChar);
|
||||
|
||||
@ -139,41 +140,53 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
return;
|
||||
}
|
||||
|
||||
if (_copy)
|
||||
if (0 < Folders.Count)
|
||||
{
|
||||
Folder<T> rootFrom = null;
|
||||
if (0 < Folders.Count)
|
||||
{
|
||||
rootFrom = await FolderDao.GetRootFolderAsync(Folders[0]);
|
||||
}
|
||||
var firstFolder = await FolderDao.GetFolderAsync(Folders[0]);
|
||||
|
||||
if (0 < Files.Count)
|
||||
if (_copy && !await FilesSecurity.CanCopyAsync(firstFolder))
|
||||
{
|
||||
rootFrom = await FolderDao.GetRootFolderByFileAsync(Files[0]);
|
||||
}
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_CopyFolder;
|
||||
|
||||
if (rootFrom != null)
|
||||
return;
|
||||
}
|
||||
else if (!_copy && !await FilesSecurity.CanMoveAsync(firstFolder))
|
||||
{
|
||||
if (rootFrom.FolderType == FolderType.TRASH)
|
||||
{
|
||||
throw new InvalidOperationException("Can not copy from Trash.");
|
||||
}
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFile;
|
||||
|
||||
if (rootFrom.FolderType == FolderType.Archive)
|
||||
{
|
||||
throw new InvalidOperationException("Can not copy from Archive.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (toFolder.RootFolderType == FolderType.TRASH)
|
||||
if (0 < Files.Count)
|
||||
{
|
||||
var firstFile = await FileDao.GetFileAsync(Files[0]);
|
||||
|
||||
if (_copy && !await FilesSecurity.CanCopyAsync(firstFile))
|
||||
{
|
||||
throw new InvalidOperationException("Can not copy to Trash.");
|
||||
}
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_CopyFile;
|
||||
|
||||
if (toFolder.RootFolderType == FolderType.Archive)
|
||||
{
|
||||
throw new InvalidOperationException("Can not copy to Archive");
|
||||
return;
|
||||
}
|
||||
else if (!_copy && !await FilesSecurity.CanMoveAsync(firstFile))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFile;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_copy && !await fileSecurity.CanCopyToAsync(toFolder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMessage_SecurityException_CopyToFolder;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (!_copy && !await fileSecurity.CanMoveToAsync(toFolder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMessage_SecurityException_MoveToFolder;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var needToMark = new List<FileEntry<TTo>>();
|
||||
@ -191,7 +204,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<FileEntry<TTo>>> MoveOrCopyFoldersAsync<TTo>(IServiceScope scope, List<T> folderIds, Folder<TTo> toFolder, bool copy, IEnumerable<Folder<TTo>> toFolderParents)
|
||||
private async Task<List<FileEntry<TTo>>> MoveOrCopyFoldersAsync<TTo>(IServiceScope scope, List<T> folderIds, Folder<TTo> toFolder, bool copy, IEnumerable<Folder<TTo>> toFolderParents, bool checkPermissions = true)
|
||||
{
|
||||
var needToMark = new List<FileEntry<TTo>>();
|
||||
|
||||
@ -215,7 +228,6 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var folder = await FolderDao.GetFolderAsync(folderId);
|
||||
var (isError, message) = await WithErrorAsync(scope, await FileDao.GetFilesAsync(folder.Id, new OrderBy(SortedByType.AZ, true), FilterType.FilesOnly, false, Guid.Empty, string.Empty, false, true).ToListAsync());
|
||||
|
||||
var isRoom = DocSpaceHelper.IsRoom(folder.FolderType);
|
||||
|
||||
@ -223,9 +235,13 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_FolderNotFound;
|
||||
}
|
||||
else if (!await FilesSecurity.CanReadAsync(folder))
|
||||
else if (copy && checkPermissions && !await FilesSecurity.CanCopyAsync(folder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_ReadFolder;
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_CopyFolder;
|
||||
}
|
||||
else if (!copy && checkPermissions && !await FilesSecurity.CanMoveAsync(folder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
|
||||
}
|
||||
else if (!isRoom && (toFolder.FolderType == FolderType.VirtualRooms || toFolder.RootFolderType == FolderType.Archive))
|
||||
{
|
||||
@ -239,7 +255,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
|
||||
}
|
||||
else if (!await FilesSecurity.CanDownloadAsync(folder))
|
||||
else if (checkPermissions && !await FilesSecurity.CanDownloadAsync(folder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException;
|
||||
}
|
||||
@ -250,6 +266,11 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
}
|
||||
else if (!Equals(folder.ParentId ?? default, toFolderId) || _resolveType == FileConflictResolveType.Duplicate)
|
||||
{
|
||||
checkPermissions = isRoom ? false : checkPermissions;
|
||||
|
||||
var files = await FileDao.GetFilesAsync(folder.Id, new OrderBy(SortedByType.AZ, true), FilterType.FilesOnly, false, Guid.Empty, string.Empty, false, true).ToListAsync();
|
||||
var (isError, message) = await WithErrorAsync(scope, files, checkPermissions);
|
||||
|
||||
try
|
||||
{
|
||||
//if destination folder contains folder with same name then merge folders
|
||||
@ -288,12 +309,12 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
if (toFolder.ProviderId == folder.ProviderId // crossDao operation is always recursive
|
||||
&& FolderDao.UseRecursiveOperation(folder.Id, toFolderId))
|
||||
{
|
||||
await MoveOrCopyFilesAsync(scope, await FileDao.GetFilesAsync(folder.Id).ToListAsync(), newFolder, copy, toFolderParents);
|
||||
await MoveOrCopyFoldersAsync(scope, await FolderDao.GetFoldersAsync(folder.Id).Select(f => f.Id).ToListAsync(), newFolder, copy, toFolderParents);
|
||||
await MoveOrCopyFilesAsync(scope, await FileDao.GetFilesAsync(folder.Id).ToListAsync(), newFolder, copy, toFolderParents, checkPermissions);
|
||||
await MoveOrCopyFoldersAsync(scope, await FolderDao.GetFoldersAsync(folder.Id).Select(f => f.Id).ToListAsync(), newFolder, copy, toFolderParents, checkPermissions);
|
||||
|
||||
if (!copy)
|
||||
{
|
||||
if (!await FilesSecurity.CanDeleteAsync(folder))
|
||||
if (checkPermissions && !await FilesSecurity.CanMoveAsync(folder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
|
||||
}
|
||||
@ -329,7 +350,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
sb.Append($"folder_{newFolderId}{SplitChar}");
|
||||
}
|
||||
}
|
||||
else if (!await FilesSecurity.CanDeleteAsync(folder))
|
||||
else if (checkPermissions && !await FilesSecurity.CanMoveAsync(folder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
|
||||
}
|
||||
@ -360,7 +381,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!await FilesSecurity.CanDeleteAsync(folder))
|
||||
if (checkPermissions && !await FilesSecurity.CanMoveAsync(folder))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
|
||||
}
|
||||
@ -453,7 +474,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
return needToMark;
|
||||
}
|
||||
|
||||
private async Task<List<FileEntry<TTo>>> MoveOrCopyFilesAsync<TTo>(IServiceScope scope, List<T> fileIds, Folder<TTo> toFolder, bool copy, IEnumerable<Folder<TTo>> toParentFolders)
|
||||
private async Task<List<FileEntry<TTo>>> MoveOrCopyFilesAsync<TTo>(IServiceScope scope, List<T> fileIds, Folder<TTo> toFolder, bool copy, IEnumerable<Folder<TTo>> toParentFolders, bool checkPermissions = true)
|
||||
{
|
||||
var needToMark = new List<FileEntry<TTo>>();
|
||||
|
||||
@ -475,7 +496,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
CancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var file = await FileDao.GetFileAsync(fileId);
|
||||
var (isError, message) = await WithErrorAsync(scope, new[] { file });
|
||||
var (isError, message) = await WithErrorAsync(scope, new[] { file }, checkPermissions);
|
||||
|
||||
if (file == null)
|
||||
{
|
||||
@ -485,11 +506,15 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFile;
|
||||
}
|
||||
else if (!await FilesSecurity.CanReadAsync(file))
|
||||
else if (copy && !await FilesSecurity.CanCopyAsync(file))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_ReadFile;
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_CopyFile;
|
||||
}
|
||||
else if (!await FilesSecurity.CanDownloadAsync(file))
|
||||
else if (!copy && checkPermissions && !await FilesSecurity.CanMoveAsync(file))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException_MoveFile;
|
||||
}
|
||||
else if (checkPermissions && !await FilesSecurity.CanDownloadAsync(file))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException;
|
||||
}
|
||||
@ -597,7 +622,7 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
{
|
||||
if (_resolveType == FileConflictResolveType.Overwrite)
|
||||
{
|
||||
if (!await FilesSecurity.CanEditAsync(conflict))
|
||||
if (checkPermissions && !await FilesSecurity.CanEditAsync(conflict))
|
||||
{
|
||||
this[Err] = FilesCommonResource.ErrorMassage_SecurityException;
|
||||
}
|
||||
@ -710,20 +735,20 @@ class FileMoveCopyOperation<T> : FileOperation<FileMoveCopyOperationData<T>, T>
|
||||
return needToMark;
|
||||
}
|
||||
|
||||
private async Task<(bool isError, string message)> WithErrorAsync(IServiceScope scope, IEnumerable<File<T>> files)
|
||||
private async Task<(bool isError, string message)> WithErrorAsync(IServiceScope scope, IEnumerable<File<T>> files, bool checkPermissions = true)
|
||||
{
|
||||
var entryManager = scope.ServiceProvider.GetService<EntryManager>();
|
||||
var fileTracker = scope.ServiceProvider.GetService<FileTrackerHelper>();
|
||||
string error = null;
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (!await FilesSecurity.CanDeleteAsync(file))
|
||||
if(checkPermissions && !await FilesSecurity.CanMoveAsync(file))
|
||||
{
|
||||
error = FilesCommonResource.ErrorMassage_SecurityException_MoveFile;
|
||||
|
||||
return (true, error);
|
||||
}
|
||||
if (await entryManager.FileLockedForMeAsync(file.Id))
|
||||
if (checkPermissions && await entryManager.FileLockedForMeAsync(file.Id))
|
||||
{
|
||||
error = FilesCommonResource.ErrorMassage_LockedFile;
|
||||
|
||||
|
@ -41,6 +41,7 @@ public class AceWrapper : IMapFrom<RoomInvitation>
|
||||
public string Email { get; set; }
|
||||
public SubjectType SubjectType { get; set; }
|
||||
public FileShareOptions FileShareOptions { get; set; }
|
||||
public bool CanEditAccess { get; set; }
|
||||
|
||||
[JsonPropertyName("title")]
|
||||
public string SubjectName { get; set; }
|
||||
|
@ -216,7 +216,7 @@ public class EntryStatusManager
|
||||
|
||||
var tagDao = _daoFactory.GetTagDao<T>();
|
||||
|
||||
var tagsTask = tagDao.GetTagsAsync(_authContext.CurrentAccount.ID, new[] { TagType.Favorite, TagType.Template, TagType.Locked }, files);
|
||||
var tagsTask = tagDao.GetTagsAsync(TagType.Locked, files).ToDictionaryAsync(k => k.EntryId, v => v);
|
||||
var tagsNewTask = tagDao.GetNewTagsAsync(_authContext.CurrentAccount.ID, files).ToListAsync();
|
||||
|
||||
var tags = await tagsTask;
|
||||
@ -224,34 +224,15 @@ public class EntryStatusManager
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
foreach (var t in tags)
|
||||
if (tags.TryGetValue(file.Id, out var lockedTag))
|
||||
{
|
||||
if (!t.Key.Equals(file.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var lockedBy = lockedTag.Owner;
|
||||
file.Locked = lockedBy != Guid.Empty;
|
||||
file.LockedBy = lockedBy != Guid.Empty && lockedBy != _authContext.CurrentAccount.ID
|
||||
? _global.GetUserName(lockedBy)
|
||||
: null;
|
||||
|
||||
if (t.Value.Any(r => r.Type == TagType.Favorite))
|
||||
{
|
||||
file.IsFavorite = true;
|
||||
}
|
||||
|
||||
if (t.Value.Any(r => r.Type == TagType.Template))
|
||||
{
|
||||
file.IsTemplate = true;
|
||||
}
|
||||
|
||||
var lockedTag = t.Value.FirstOrDefault(r => r.Type == TagType.Locked);
|
||||
if (lockedTag != null)
|
||||
{
|
||||
var lockedBy = lockedTag.Owner;
|
||||
file.Locked = lockedBy != Guid.Empty;
|
||||
file.LockedBy = lockedBy != Guid.Empty && lockedBy != _authContext.CurrentAccount.ID
|
||||
? _global.GetUserName(lockedBy)
|
||||
: null;
|
||||
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tagsNew.Any(r => r.EntryId.Equals(file.Id)))
|
||||
|
@ -113,7 +113,8 @@ public class FileSharingAceHelper<T>
|
||||
|
||||
foreach (var w in aceWrappers.OrderByDescending(ace => ace.SubjectGroup))
|
||||
{
|
||||
if (entry is Folder<T> folder && DocSpaceHelper.IsRoom(folder.FolderType) && !DocSpaceHelper.ValidateShare(folder.FolderType, w.Access, _userManager.IsUser(w.Id)))
|
||||
if (entry is Folder<T> folder && DocSpaceHelper.IsRoom(folder.FolderType) &&
|
||||
!DocSpaceHelper.ValidateShare(folder.FolderType, w.Access, _userManager.IsUser(w.Id)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -343,12 +344,7 @@ public class FileSharingHelper
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry.RootFolderType == FolderType.VirtualRooms && (_global.IsDocSpaceAdministrator || await _fileSecurity.CanShareAsync(entry)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (folder != null && DocSpaceHelper.IsRoom(folder.FolderType) && folder.RootFolderType != FolderType.Archive && await _fileSecurity.CanEditRoomAsync(entry))
|
||||
if (await _fileSecurity.CanEditAccessAsync(entry))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -445,6 +441,7 @@ public class FileSharing
|
||||
var result = new List<AceWrapper>();
|
||||
var shares = await _fileSecurity.GetSharesAsync(entry);
|
||||
var isRoom = entry is Folder<T> { Private: false } room && DocSpaceHelper.IsRoom(room.FolderType);
|
||||
var canEditAccess = await _fileSecurity.CanEditAccessAsync(entry);
|
||||
|
||||
var records = shares
|
||||
.GroupBy(r => r.Subject)
|
||||
@ -499,13 +496,16 @@ public class FileSharing
|
||||
Id = r.Subject,
|
||||
SubjectGroup = isgroup,
|
||||
Access = share,
|
||||
FileShareOptions = r.FileShareOptions
|
||||
FileShareOptions = r.FileShareOptions,
|
||||
};
|
||||
|
||||
w.CanEditAccess = _authContext.CurrentAccount.ID != w.Id && w.SubjectType == SubjectType.UserOrGroup && canEditAccess;
|
||||
|
||||
if (isRoom && r.IsLink)
|
||||
{
|
||||
w.Link = _roomLinkService.GetInvitationLink(r.Subject, r.Owner);
|
||||
w.SubjectGroup = true;
|
||||
w.CanEditAccess = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -560,7 +560,8 @@ public class FileSharing
|
||||
SubjectName = _global.GetUserName(ownerId),
|
||||
SubjectGroup = false,
|
||||
Access = FileShare.ReadWrite,
|
||||
Owner = true
|
||||
Owner = true,
|
||||
CanEditAccess = false,
|
||||
};
|
||||
|
||||
result.Add(w);
|
||||
|
Loading…
Reference in New Issue
Block a user