mirror of https://github.com/laurent22/joplin.git
Desktop: Fixed sharing notebook when recipient is not allowed to share
parent
8b68da4040
commit
1bb7bbb9e5
|
@ -1,6 +1,10 @@
|
||||||
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '@joplin/lib/locale';
|
||||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||||
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
|
import Logger from '@joplin/lib/Logger';
|
||||||
|
|
||||||
|
const logger = Logger.create('leaveSharedFolder');
|
||||||
|
|
||||||
export const declaration: CommandDeclaration = {
|
export const declaration: CommandDeclaration = {
|
||||||
name: 'leaveSharedFolder',
|
name: 'leaveSharedFolder',
|
||||||
|
@ -12,7 +16,24 @@ export const runtime = (): CommandRuntime => {
|
||||||
execute: async (_context: CommandContext, folderId: string = null) => {
|
execute: async (_context: CommandContext, folderId: string = null) => {
|
||||||
const answer = confirm(_('This will remove the notebook from your collection and you will no longer have access to its content. Do you wish to continue?'));
|
const answer = confirm(_('This will remove the notebook from your collection and you will no longer have access to its content. Do you wish to continue?'));
|
||||||
if (!answer) return;
|
if (!answer) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Since we are going to delete the notebook, do some extra safety checks. In particular:
|
||||||
|
// - Check that the notebook is indeed being shared.
|
||||||
|
// - Check that it does **not** belong to the current user.
|
||||||
|
|
||||||
|
const shares = await ShareService.instance().refreshShares();
|
||||||
|
const share = shares.find(s => s.folder_id === folderId);
|
||||||
|
if (!share) throw new Error(_('Could not verify the share status of this notebook - aborting. Please try again when you are connected to the internet.'));
|
||||||
|
|
||||||
|
const userId = Setting.value('sync.userId');
|
||||||
|
if (share.user.id === userId) throw new Error('Cannot leave own notebook');
|
||||||
|
|
||||||
await ShareService.instance().leaveSharedFolder(folderId);
|
await ShareService.instance().leaveSharedFolder(folderId);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error);
|
||||||
|
alert(_('Error: %s', error.message));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
enabledCondition: 'joplinServerConnected && folderIsShareRootAndNotOwnedByUser',
|
enabledCondition: 'joplinServerConnected && folderIsShareRootAndNotOwnedByUser',
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { _ } from '@joplin/lib/locale';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FolderEntity } from '@joplin/lib/services/database/types';
|
import { FolderEntity } from '@joplin/lib/services/database/types';
|
||||||
import Folder from '@joplin/lib/models/Folder';
|
import Folder from '@joplin/lib/models/Folder';
|
||||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
import ShareService, { ApiShare } from '@joplin/lib/services/share/ShareService';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import StyledFormLabel from '../style/StyledFormLabel';
|
import StyledFormLabel from '../style/StyledFormLabel';
|
||||||
import StyledInput from '../style/StyledInput';
|
import StyledInput from '../style/StyledInput';
|
||||||
|
@ -167,11 +167,38 @@ function ShareFolderDialog(props: Props) {
|
||||||
|
|
||||||
async function shareRecipient_click() {
|
async function shareRecipient_click() {
|
||||||
setShareState(ShareState.Creating);
|
setShareState(ShareState.Creating);
|
||||||
|
setLatestError(null);
|
||||||
|
|
||||||
|
let errorSet = false;
|
||||||
|
|
||||||
|
const handleError = (error: any) => {
|
||||||
|
if (!errorSet) setLatestError(error);
|
||||||
|
errorSet = true;
|
||||||
|
logger.error(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
const defer = (error: any) => {
|
||||||
|
if (error) handleError(error);
|
||||||
|
setShareState(ShareState.Idle);
|
||||||
|
};
|
||||||
|
|
||||||
|
let share: ApiShare = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
share = await ShareService.instance().shareFolder(props.folderId);
|
||||||
|
} catch (error) {
|
||||||
|
return defer(error);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setLatestError(null);
|
|
||||||
const share = await ShareService.instance().shareFolder(props.folderId);
|
|
||||||
await ShareService.instance().addShareRecipient(share.id, share.master_key_id, recipientEmail);
|
await ShareService.instance().addShareRecipient(share.id, share.master_key_id, recipientEmail);
|
||||||
|
} catch (error) {
|
||||||
|
// Handle the error but continue the process because we need to at
|
||||||
|
// least refresh the shares since one has been created above.
|
||||||
|
handleError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
ShareService.instance().refreshShares(),
|
ShareService.instance().refreshShares(),
|
||||||
ShareService.instance().refreshShareUsers(share.id),
|
ShareService.instance().refreshShareUsers(share.id),
|
||||||
|
@ -180,10 +207,9 @@ function ShareFolderDialog(props: Props) {
|
||||||
|
|
||||||
await synchronize();
|
await synchronize();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
handleError(error);
|
||||||
setLatestError(error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setShareState(ShareState.Idle);
|
defer(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue