mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Chore: Moved share invitation response logic to separate file (Desktop)
This commit is contained in:
parent
a5f2fd8982
commit
8a7fa78c54
@ -732,6 +732,9 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js.map
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.d.ts
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js.map
|
||||
packages/app-desktop/services/share/invitationRespond.d.ts
|
||||
packages/app-desktop/services/share/invitationRespond.js
|
||||
packages/app-desktop/services/share/invitationRespond.js.map
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.d.ts
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js.map
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -715,6 +715,9 @@ packages/app-desktop/services/plugins/hooks/useViewIsReady.js.map
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.d.ts
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js
|
||||
packages/app-desktop/services/plugins/hooks/useWebviewToPluginMessages.js.map
|
||||
packages/app-desktop/services/share/invitationRespond.d.ts
|
||||
packages/app-desktop/services/share/invitationRespond.js
|
||||
packages/app-desktop/services/share/invitationRespond.js.map
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.d.ts
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js
|
||||
packages/app-desktop/services/spellChecker/SpellCheckerServiceDriverNative.js.map
|
||||
|
@ -32,21 +32,17 @@ import removeItem from '../ResizableLayout/utils/removeItem';
|
||||
import EncryptionService from '@joplin/lib/services/e2ee/EncryptionService';
|
||||
import ShareFolderDialog from '../ShareFolderDialog/ShareFolderDialog';
|
||||
import { ShareInvitation } from '@joplin/lib/services/share/reducer';
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import removeKeylessItems from '../ResizableLayout/utils/removeKeylessItems';
|
||||
import { localSyncInfoFromState } from '@joplin/lib/services/synchronizer/syncInfoUtils';
|
||||
import { showMissingMasterKeyMessage } from '@joplin/lib/services/e2ee/utils';
|
||||
import commands from './commands/index';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import invitationRespond from '../../services/share/invitationRespond';
|
||||
const { connect } = require('react-redux');
|
||||
const { PromptDialog } = require('../PromptDialog.min.js');
|
||||
const NotePropertiesDialog = require('../NotePropertiesDialog.min.js');
|
||||
const PluginManager = require('@joplin/lib/services/PluginManager');
|
||||
const ipcRenderer = require('electron').ipcRenderer;
|
||||
|
||||
const logger = Logger.create('MainScreen');
|
||||
|
||||
interface LayerModalState {
|
||||
visible: boolean;
|
||||
message: string;
|
||||
@ -549,26 +545,8 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
bridge().restart();
|
||||
};
|
||||
|
||||
const onInvitationRespond = async (shareUserId: string, accept: boolean) => {
|
||||
// The below functions can take a bit of time to complete so in the
|
||||
// meantime we hide the notification so that the user doesn't click
|
||||
// multiple times on the Accept link.
|
||||
ShareService.instance().setProcessingShareInvitationResponse(true);
|
||||
|
||||
try {
|
||||
await ShareService.instance().respondInvitation(shareUserId, accept);
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
alert(_('Could not respond to the invitation. Please try again, or check with the notebook owner if they are still sharing it.\n\nThe error was: "%s"', error.message));
|
||||
}
|
||||
|
||||
try {
|
||||
await ShareService.instance().refreshShareInvitations();
|
||||
} finally {
|
||||
ShareService.instance().setProcessingShareInvitationResponse(false);
|
||||
}
|
||||
|
||||
void reg.scheduleSync(1000);
|
||||
const onInvitationRespond = async (shareUserId: string, folderId: string, accept: boolean) => {
|
||||
await invitationRespond(shareUserId, folderId, accept);
|
||||
};
|
||||
|
||||
let msg = null;
|
||||
@ -613,9 +591,9 @@ class MainScreenComponent extends React.Component<Props, State> {
|
||||
msg = this.renderNotificationMessage(
|
||||
_('%s (%s) would like to share a notebook with you.', sharer.full_name, sharer.email),
|
||||
_('Accept'),
|
||||
() => onInvitationRespond(invitation.id, true),
|
||||
() => onInvitationRespond(invitation.id, invitation.share.folder_id, true),
|
||||
_('Reject'),
|
||||
() => onInvitationRespond(invitation.id, false)
|
||||
() => onInvitationRespond(invitation.id, invitation.share.folder_id, false)
|
||||
);
|
||||
} else if (this.props.hasDisabledSyncItems) {
|
||||
msg = this.renderNotificationMessage(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CommandRuntime, CommandDeclaration, CommandContext } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
|
||||
export const declaration: CommandDeclaration = {
|
||||
name: 'leaveSharedFolder',
|
||||
@ -12,16 +12,7 @@ export const runtime = (): CommandRuntime => {
|
||||
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?'));
|
||||
if (!answer) return;
|
||||
|
||||
// In that case, we should only delete the folder but none of its
|
||||
// children. Deleting the folder tells the server that we want to
|
||||
// leave the share. The server will then proceed to delete all
|
||||
// associated user_items. So eventually all the notebook content
|
||||
// will also be deleted for the current user.
|
||||
//
|
||||
// We don't delete the children here because that would delete them
|
||||
// for the other share participants too.
|
||||
await Folder.delete(folderId, { deleteChildren: false });
|
||||
await ShareService.instance().leaveSharedFolder(folderId);
|
||||
},
|
||||
enabledCondition: 'joplinServerConnected && folderIsShareRootAndNotOwnedByUser',
|
||||
};
|
||||
|
60
packages/app-desktop/services/share/invitationRespond.ts
Normal file
60
packages/app-desktop/services/share/invitationRespond.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import ShareService from '@joplin/lib/services/share/ShareService';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
||||
const logger = Logger.create('invitationRespond');
|
||||
|
||||
export default async function(shareUserId: string, folderId: string, accept: boolean) {
|
||||
// The below functions can take a bit of time to complete so in the
|
||||
// meantime we hide the notification so that the user doesn't click
|
||||
// multiple times on the Accept link.
|
||||
ShareService.instance().setProcessingShareInvitationResponse(true);
|
||||
|
||||
try {
|
||||
await ShareService.instance().respondInvitation(shareUserId, accept);
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
alert(_('Could not respond to the invitation. Please try again, or check with the notebook owner if they are still sharing it.\n\nThe error was: "%s"', error.message));
|
||||
}
|
||||
|
||||
// This is to handle an edge case that can happen if:
|
||||
//
|
||||
// - The user is a recipient of a share.
|
||||
// - The sender removes the recipient from the share, then add him again.
|
||||
// - The recipient gets the invitation, but reply "Reject" to it.
|
||||
//
|
||||
// If we don't handle this case, it would kind of work but would create
|
||||
// conflicts because the shared notes would be converted to local ones, then
|
||||
// during sync the synchronizer would try to delete them. Since they've been
|
||||
// changed, they'll all be marked as conflicts.
|
||||
//
|
||||
// So the simplest thing to do is to leave the folder, which is most likely
|
||||
// what the user wants. And if not, it's always possible to ask the sender
|
||||
// to share again.
|
||||
//
|
||||
// NOTE: DOESN'T WORK. Because Folder.updateAllShareIds() would still run
|
||||
// and change the notes share_id property, thus creating conflicts again.
|
||||
// Leaving it as it is for now, as it's an unlikely scenario and it won't
|
||||
// cause any data loss.
|
||||
|
||||
console.info('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', shareUserId, folderId);
|
||||
console.info('ALL', await Folder.all());
|
||||
|
||||
if (!accept) {
|
||||
const existingFolder = await Folder.load(folderId);
|
||||
if (existingFolder) {
|
||||
logger.warn('Rejected an invitation, but the folder was already there. Conflicts are likely to happen. ShareUserId:', shareUserId, 'Folder ID:', folderId);
|
||||
// await ShareService.instance().leaveSharedFolder(folderId);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await ShareService.instance().refreshShareInvitations();
|
||||
} finally {
|
||||
ShareService.instance().setProcessingShareInvitationResponse(false);
|
||||
}
|
||||
|
||||
void reg.scheduleSync(1000);
|
||||
}
|
@ -117,6 +117,20 @@ export default class ShareService {
|
||||
await Folder.updateAllShareIds();
|
||||
}
|
||||
|
||||
// This is when a share recipient decides to leave the shared folder.
|
||||
//
|
||||
// In that case, we should only delete the folder but none of its children.
|
||||
// Deleting the folder tells the server that we want to leave the share. The
|
||||
// server will then proceed to delete all associated user_items. So
|
||||
// eventually all the notebook content will also be deleted for the current
|
||||
// user.
|
||||
//
|
||||
// We don't delete the children here because that would delete them for the
|
||||
// other share participants too.
|
||||
public async leaveSharedFolder(folderId: string): Promise<void> {
|
||||
await Folder.delete(folderId, { deleteChildren: false });
|
||||
}
|
||||
|
||||
public async shareNote(noteId: string): Promise<StateShare> {
|
||||
const note = await Note.load(noteId);
|
||||
if (!note) throw new Error(`No such note: ${noteId}`);
|
||||
|
Loading…
Reference in New Issue
Block a user