From 28ed51f78bdb66af4bb37dd5a6ab30ec6051ac42 Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Tue, 28 Feb 2023 15:33:27 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=81=20Drive=20fix=20QA=20issues=20(#27?= =?UTF-8?q?64)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Partial fixes on #2763 * Fix preview with OnlyOffice * Fix access level and onlyoffice edition --- .../node/src/services/documents/utils.ts | 49 ++++++----- .../hooks/use-company-applications.ts | 20 +++-- .../state/company-applications.ts | 5 +- .../app/features/auth/jwt-storage-service.ts | 6 +- .../features/drive/hooks/use-drive-preview.ts | 9 +- .../features/drive/hooks/use-drive-upload.tsx | 85 ++++++++++--------- .../app/views/applications/drive/browser.tsx | 6 +- .../drive/components/select-users.tsx | 2 +- .../app/views/applications/drive/index.tsx | 12 ++- .../drive/modals/create/index.tsx | 5 +- .../modals/update-access/internal-access.tsx | 2 - .../app/views/applications/drive/shared.tsx | 2 +- .../applications/viewer/drive-display.tsx | 2 +- .../app/views/client/main-view/MainView.tsx | 11 ++- 14 files changed, 123 insertions(+), 93 deletions(-) diff --git a/twake/backend/node/src/services/documents/utils.ts b/twake/backend/node/src/services/documents/utils.ts index 0f32b0dcaf..cf76c14a3d 100644 --- a/twake/backend/node/src/services/documents/utils.ts +++ b/twake/backend/node/src/services/documents/utils.ts @@ -378,35 +378,34 @@ export const getAccessLevel = async ( if (itemToken === publicToken) return itemLevel; } - //From there a user must be logged in - if (!context.user.id) return "none"; - const accessEntities = item.access_info.entities || []; + const otherLevels = []; - //Users - const matchingUser = accessEntities.find(a => a.type === "user" && a.id === context.user?.id); - if (matchingUser) return matchingUser.level; - - //Channels - if (context.twake_tab_token) { - try { - const [channelId] = context.twake_tab_token.split("+"); //First item will be the channel id - const matchingChannel = accessEntities.find( - a => a.type === "channel" && a.id === channelId, - ); - if (matchingChannel) return matchingChannel.level; - } catch (e) { - console.log(e); + //From there a user must be logged in + if (context?.user?.id) { + //Users + const matchingUser = accessEntities.find(a => a.type === "user" && a.id === context.user?.id); + if (matchingUser) return matchingUser.level; + + //Channels + if (context.twake_tab_token) { + try { + const [channelId] = context.twake_tab_token.split("+"); //First item will be the channel id + const matchingChannel = accessEntities.find( + a => a.type === "channel" && a.id === channelId, + ); + if (matchingChannel) return matchingChannel.level; + } catch (e) { + console.log(e); + } } - } - - const otherLevels = []; - //Companies - const matchingCompany = accessEntities.find( - a => a.type === "company" && a.id === context.company.id, - ); - if (matchingCompany) otherLevels.push(matchingCompany.level); + //Companies + const matchingCompany = accessEntities.find( + a => a.type === "company" && a.id === context.company.id, + ); + if (matchingCompany) otherLevels.push(matchingCompany.level); + } //Parent folder const maxParentFolderLevel = diff --git a/twake/frontend/src/app/features/applications/hooks/use-company-applications.ts b/twake/frontend/src/app/features/applications/hooks/use-company-applications.ts index c9528893e1..4e82ac281a 100644 --- a/twake/frontend/src/app/features/applications/hooks/use-company-applications.ts +++ b/twake/frontend/src/app/features/applications/hooks/use-company-applications.ts @@ -13,6 +13,8 @@ import { useRealtimeRoom } from 'app/features/global/hooks/use-realtime'; import { Application } from 'app/features/applications/types/application'; import { LoadingState } from 'app/features/global/state/atoms/Loading'; import useRouterWorkspace from 'app/features/router/hooks/use-router-workspace'; +import { useGlobalEffect } from 'app/features/global/hooks/use-global-effect'; +import useRouterCompany from 'app/features/router/hooks/use-router-company'; const logger = Logger.getLogger('useApplications'); /** @@ -21,8 +23,8 @@ const logger = Logger.getLogger('useApplications'); * @returns */ export function useCompanyApplications(companyId = '') { - const { company } = useCurrentCompany(); - companyId = companyId || company?.id || ''; + const routerCompanyId = useRouterCompany(); + companyId = companyId || routerCompanyId || ''; const workspaceId = useRouterWorkspace(); const [applications, setApplications] = useRecoilState(CompanyApplicationsStateFamily(companyId)); @@ -42,12 +44,16 @@ export function useCompanyApplications(companyId = '') { onChangeCompanyApplications(companyId, applications); }, [applications]); - useEffect(() => { - refresh(); - }, [workspaceId]); + useGlobalEffect( + 'useCompanyApplications', + () => { + refresh(); + }, + [workspaceId], + ); - const get = (applicationId: string) => { - return applications.find(a => a.id === applicationId); + const get = (applicationId: string): Application | null => { + return applications.find(a => a.id === applicationId) || null; }; const remove = async (applicationId: string) => { diff --git a/twake/frontend/src/app/features/applications/state/company-applications.ts b/twake/frontend/src/app/features/applications/state/company-applications.ts index c49947bf60..86574fb212 100644 --- a/twake/frontend/src/app/features/applications/state/company-applications.ts +++ b/twake/frontend/src/app/features/applications/state/company-applications.ts @@ -36,8 +36,5 @@ export const CompanyApplicationsStateFamily = atomFamily( export const fetchCompanyApplications = selectorFamily({ key: 'fetchCompanyApplications', - get: companyId => async () => { - logger.debug('fetchCompanyApplications', companyId); - return (await CompanyApplicationsAPIClient.list(companyId)) || []; - }, + get: companyId => () => [], }); diff --git a/twake/frontend/src/app/features/auth/jwt-storage-service.ts b/twake/frontend/src/app/features/auth/jwt-storage-service.ts index ae9599893d..21d126a058 100755 --- a/twake/frontend/src/app/features/auth/jwt-storage-service.ts +++ b/twake/frontend/src/app/features/auth/jwt-storage-service.ts @@ -126,7 +126,11 @@ class JWTStorage { } authenticateCall(callback?: () => void) { - if (this.isAccessExpired() && LoginService.currentUserId) { + if ( + this.isAccessExpired() && + LoginService.currentUserId && + !document.location.pathname.includes('/shared/') + ) { this.logger.debug('authenticateCall: Updating user because the access token expired'); this.renew() .then(() => { diff --git a/twake/frontend/src/app/features/drive/hooks/use-drive-preview.ts b/twake/frontend/src/app/features/drive/hooks/use-drive-preview.ts index 3c9554bfd8..bf7d3ff75e 100644 --- a/twake/frontend/src/app/features/drive/hooks/use-drive-preview.ts +++ b/twake/frontend/src/app/features/drive/hooks/use-drive-preview.ts @@ -69,12 +69,15 @@ export const useDrivePreviewDisplayData = () => { const name = status.details?.item.last_version_cache.file_metadata.name || status.details?.item.name || ''; const extension = name.split('.').pop(); - const type = fileUploadApiClient.mimeToType(status.details?.item.last_version_cache.file_metadata.mime || '', extension); + const type = fileUploadApiClient.mimeToType( + status.details?.item.last_version_cache.file_metadata.mime || '', + extension, + ); const id = status.details?.item.last_version_cache.file_metadata.external_id || ''; const download = fileUploadService.getDownloadRoute({ companyId: status.item?.company_id || '', - fileId: status.details?.item.last_version_cache.file_metadata.external_id || '' + fileId: status.details?.item.last_version_cache.file_metadata.external_id || '', }); - return { download, id, name, type, extension } + return { download, id, name, type, extension }; }; diff --git a/twake/frontend/src/app/features/drive/hooks/use-drive-upload.tsx b/twake/frontend/src/app/features/drive/hooks/use-drive-upload.tsx index d6332c71a9..35a1ec2ca1 100644 --- a/twake/frontend/src/app/features/drive/hooks/use-drive-upload.tsx +++ b/twake/frontend/src/app/features/drive/hooks/use-drive-upload.tsx @@ -110,51 +110,54 @@ export const useDriveUpload = () => { } }; - const uploadFromUrl = - (url: string, name: string, context: { companyId: string; parentId: string }) => () => { - const request = new XMLHttpRequest(); - request.open('GET', url, true); - request.responseType = 'blob'; - request.onload = function () { - try { - const file = new File([request.response], name); - FileUploadService.upload([file], { - context: { - companyId: context.companyId, - parentId: context.parentId, - }, - callback: (file, context) => { - if (file) { - create( - { - company_id: context.companyId, - workspace_id: 'drive', //We don't set workspace ID for now - parent_id: context.parentId, + const uploadFromUrl = ( + url: string, + name: string, + context: { companyId: string; parentId: string }, + ) => { + const request = new XMLHttpRequest(); + request.open('GET', url, true); + request.responseType = 'blob'; + request.onload = function () { + try { + const file = new File([request.response], name); + FileUploadService.upload([file], { + context: { + companyId: context.companyId, + parentId: context.parentId, + }, + callback: (file, context) => { + if (file) { + create( + { + company_id: context.companyId, + workspace_id: 'drive', //We don't set workspace ID for now + parent_id: context.parentId, + name: file.metadata?.name, + size: file.upload_data?.size, + }, + { + provider: 'internal', + application_id: '', + file_metadata: { name: file.metadata?.name, size: file.upload_data?.size, + mime: file.metadata?.mime, + thumbnails: file?.thumbnails, + source: 'internal', + external_id: file.id, }, - { - provider: 'internal', - application_id: '', - file_metadata: { - name: file.metadata?.name, - size: file.upload_data?.size, - mime: file.metadata?.mime, - thumbnails: file?.thumbnails, - source: 'internal', - external_id: file.id, - }, - }, - ); - } - }, - }); - } catch (e) { - ToasterService.error('Error while creating an empty file.'); - } - }; - request.send(); + }, + ); + } + }, + }); + } catch (e) { + ToasterService.error('Error while creating an empty file.'); + } }; + request.send(); + }; return { uploadTree, uploadFromUrl, uploadVersion }; }; diff --git a/twake/frontend/src/app/views/applications/drive/browser.tsx b/twake/frontend/src/app/views/applications/drive/browser.tsx index c46c48f1de..4ac11cbe43 100644 --- a/twake/frontend/src/app/views/applications/drive/browser.tsx +++ b/twake/frontend/src/app/views/applications/drive/browser.tsx @@ -38,9 +38,11 @@ export default memo( ({ initialParentId, twakeTabContextToken, + inPublicSharing, }: { initialParentId?: string; twakeTabContextToken?: string; + inPublicSharing?: boolean; }) => { const companyId = useRouterCompany(); setTwakeTabToken(twakeTabContextToken || null); @@ -68,7 +70,7 @@ export default memo( useEffect(() => { setChecked({}); refresh(parentId); - refresh('trash'); + if (!inPublicSharing) refresh('trash'); }, [parentId, refresh]); const openItemModal = useCallback(() => { @@ -131,7 +133,7 @@ export default memo( (loading && !children?.length ? 'opacity-50 ' : '') } > - {document.location.origin.includes('canary') && ( + {document.location.origin.includes('canary') && access !== 'read' && (
Welcome to the next version of Twake Drive. diff --git a/twake/frontend/src/app/views/applications/drive/components/select-users.tsx b/twake/frontend/src/app/views/applications/drive/components/select-users.tsx index 6b292584ba..33eafccf93 100644 --- a/twake/frontend/src/app/views/applications/drive/components/select-users.tsx +++ b/twake/frontend/src/app/views/applications/drive/components/select-users.tsx @@ -21,7 +21,7 @@ export default (props: { const inputElement = useRef(null); useEffect(() => { - props.onChange(users); + if (users.length) props.onChange(users); }, [users]); return ( diff --git a/twake/frontend/src/app/views/applications/drive/index.tsx b/twake/frontend/src/app/views/applications/drive/index.tsx index 5e6e068367..2855146e57 100644 --- a/twake/frontend/src/app/views/applications/drive/index.tsx +++ b/twake/frontend/src/app/views/applications/drive/index.tsx @@ -12,14 +12,20 @@ export type EmbedContext = { export default ({ initialParentId, context, + inPublicSharing, }: { initialParentId?: string; context?: EmbedContext; + inPublicSharing?: boolean; }) => { return ( <> - + ); }; @@ -27,13 +33,15 @@ export default ({ const Drive = ({ initialParentId, context, + inPublicSharing, }: { initialParentId?: string; context?: EmbedContext; + inPublicSharing?: boolean; }) => { if (context?.tabId) { return ; } - return ; + return ; }; diff --git a/twake/frontend/src/app/views/applications/drive/modals/create/index.tsx b/twake/frontend/src/app/views/applications/drive/modals/create/index.tsx index cf3cebdc97..9827eca922 100644 --- a/twake/frontend/src/app/views/applications/drive/modals/create/index.tsx +++ b/twake/frontend/src/app/views/applications/drive/modals/create/index.tsx @@ -6,6 +6,7 @@ import A from 'app/atoms/link'; import { Modal, ModalContent } from 'app/atoms/modal'; import { Base } from 'app/atoms/text'; import { useApplications } from 'app/features/applications/hooks/use-applications'; +import { useCompanyApplications } from 'app/features/applications/hooks/use-company-applications'; import { Application } from 'app/features/applications/types/application'; import { ReactNode } from 'react'; import { atom, useRecoilState } from 'recoil'; @@ -34,7 +35,7 @@ export const CreateModal = ({ addFromUrl: (url: string, name: string) => void; }) => { const [state, setState] = useRecoilState(CreateModalAtom); - const { applications } = useApplications(); + const { applications } = useCompanyApplications(); return ( } - text={`${app.emptyFile.name} (${app.app.identity?.name})`} + text={`${app.emptyFile.name}`} onClick={() => addFromUrl(app.emptyFile.url, app.emptyFile.name)} /> ); diff --git a/twake/frontend/src/app/views/applications/drive/modals/update-access/internal-access.tsx b/twake/frontend/src/app/views/applications/drive/modals/update-access/internal-access.tsx index 7ae3b860d2..fa01fd443f 100644 --- a/twake/frontend/src/app/views/applications/drive/modals/update-access/internal-access.tsx +++ b/twake/frontend/src/app/views/applications/drive/modals/update-access/internal-access.tsx @@ -14,8 +14,6 @@ import { AccessLevel } from './common'; export const InternalAccessManager = ({ id, disabled }: { id: string; disabled: boolean }) => { const { item, loading, update } = useDriveItem(id); - console.log(item?.access_info.entities); - const userEntities = item?.access_info.entities.filter(a => a.type === 'user') || []; const folderEntity = item?.access_info.entities.filter(a => a.type === 'folder')?.[0] || { type: 'folder', diff --git a/twake/frontend/src/app/views/applications/drive/shared.tsx b/twake/frontend/src/app/views/applications/drive/shared.tsx index d4711a9096..22760bd411 100755 --- a/twake/frontend/src/app/views/applications/drive/shared.tsx +++ b/twake/frontend/src/app/views/applications/drive/shared.tsx @@ -66,7 +66,7 @@ export default () => {
- +
diff --git a/twake/frontend/src/app/views/applications/viewer/drive-display.tsx b/twake/frontend/src/app/views/applications/viewer/drive-display.tsx index 19a506352f..ecf0ece4ba 100644 --- a/twake/frontend/src/app/views/applications/viewer/drive-display.tsx +++ b/twake/frontend/src/app/views/applications/viewer/drive-display.tsx @@ -15,7 +15,7 @@ export default (): React.ReactElement => { const { isOpen } = useDrivePreviewModal(); const { loading, setLoading } = useDrivePreviewLoading(); - if (!download || !isOpen) { + if (!download || !isOpen || !id) { return <>; } diff --git a/twake/frontend/src/app/views/client/main-view/MainView.tsx b/twake/frontend/src/app/views/client/main-view/MainView.tsx index 5217e590a0..4effb8993d 100644 --- a/twake/frontend/src/app/views/client/main-view/MainView.tsx +++ b/twake/frontend/src/app/views/client/main-view/MainView.tsx @@ -109,4 +109,13 @@ export const MainContentWrapper = () => { return ; }; -export default MainView; +export default ({ className }: PropsType) => { + //This is a hack because main view is displayed before we detect the current "channel" is in fact an application + const channelId = useRouterChannel(); + const { applications } = useCompanyApplications(); + const isChannelMember = useIsChannelMember(channelId); + + if (applications.length === 0 && !isChannelMember) return <>; + + return ; +};