mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-16 19:57:52 +01:00
Merge pull request #8743 from 01zulfi/editor/restrict-attachment-for-notloggedin-users
editor: restrict attachment upload for not logged-in users
This commit is contained in:
@@ -59,6 +59,7 @@ export type Settings = {
|
|||||||
fontScale: number;
|
fontScale: number;
|
||||||
markdownShortcuts: boolean;
|
markdownShortcuts: boolean;
|
||||||
features: Record<any, any>;
|
features: Record<any, any>;
|
||||||
|
loggedIn: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EditorProps = {
|
export type EditorProps = {
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ export const useEditorEvents = (
|
|||||||
state.timeFormat
|
state.timeFormat
|
||||||
]);
|
]);
|
||||||
const handleBack = useRef<NativeEventSubscription>();
|
const handleBack = useRef<NativeEventSubscription>();
|
||||||
|
const loggedIn = useUserStore((state) => !!state.user);
|
||||||
const { fontScale } = useWindowDimensions();
|
const { fontScale } = useWindowDimensions();
|
||||||
|
|
||||||
const doubleSpacedLines = useSettingStore(
|
const doubleSpacedLines = useSettingStore(
|
||||||
@@ -224,7 +225,8 @@ export const useEditorEvents = (
|
|||||||
timeFormat: db.settings?.getTimeFormat(),
|
timeFormat: db.settings?.getTimeFormat(),
|
||||||
fontScale,
|
fontScale,
|
||||||
markdownShortcuts,
|
markdownShortcuts,
|
||||||
features
|
features,
|
||||||
|
loggedIn
|
||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
fullscreen,
|
fullscreen,
|
||||||
@@ -242,7 +244,8 @@ export const useEditorEvents = (
|
|||||||
timeFormat,
|
timeFormat,
|
||||||
loading,
|
loading,
|
||||||
fontScale,
|
fontScale,
|
||||||
markdownShortcuts
|
markdownShortcuts,
|
||||||
|
loggedIn
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const onBackPress = useCallback(async () => {
|
const onBackPress = useCallback(async () => {
|
||||||
@@ -556,9 +559,17 @@ export const useEditorEvents = (
|
|||||||
if (editor.state.current?.isFocused) {
|
if (editor.state.current?.isFocused) {
|
||||||
editor.state.current.isFocused = true;
|
editor.state.current.isFocused = true;
|
||||||
}
|
}
|
||||||
PaywallSheet.present(
|
if (editorMessage.value.feature === "insertAttachment") {
|
||||||
await isFeatureAvailable(editorMessage.value.feature)
|
ToastManager.show({
|
||||||
);
|
type: "info",
|
||||||
|
message: strings.loginRequired()
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
PaywallSheet.present(
|
||||||
|
await isFeatureAvailable(editorMessage.value.feature)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case EditorEvents.monograph:
|
case EditorEvents.monograph:
|
||||||
publishNote();
|
publishNote();
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import {
|
|||||||
useStore as useAppStore,
|
useStore as useAppStore,
|
||||||
store as appstore
|
store as appstore
|
||||||
} from "../../stores/app-store";
|
} from "../../stores/app-store";
|
||||||
|
import { useStore as useUserStore } from "../../stores/user-store";
|
||||||
import { useStore as useSearchStore } from "../../stores/search-store";
|
import { useStore as useSearchStore } from "../../stores/search-store";
|
||||||
import { AppEventManager, AppEvents } from "../../common/app-events";
|
import { AppEventManager, AppEvents } from "../../common/app-events";
|
||||||
import { FlexScrollContainer } from "../scroll-container";
|
import { FlexScrollContainer } from "../scroll-container";
|
||||||
@@ -77,6 +78,7 @@ import { Pane, SplitPane } from "../split-pane";
|
|||||||
import { TITLE_BAR_HEIGHT } from "../title-bar";
|
import { TITLE_BAR_HEIGHT } from "../title-bar";
|
||||||
import { isMobile } from "../../hooks/use-mobile";
|
import { isMobile } from "../../hooks/use-mobile";
|
||||||
import { isTablet } from "../../hooks/use-tablet";
|
import { isTablet } from "../../hooks/use-tablet";
|
||||||
|
import { ConfirmDialog } from "../../dialogs/confirm";
|
||||||
|
|
||||||
const PDFPreview = React.lazy(() => import("../pdf-preview"));
|
const PDFPreview = React.lazy(() => import("../pdf-preview"));
|
||||||
|
|
||||||
@@ -604,6 +606,15 @@ export function Editor(props: EditorProps) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onInsertAttachment={async (type) => {
|
onInsertAttachment={async (type) => {
|
||||||
|
if (!useUserStore.getState().isLoggedIn) {
|
||||||
|
ConfirmDialog.show({
|
||||||
|
title: strings.notLoggedIn(),
|
||||||
|
message: strings.loginToUploadAttachments(),
|
||||||
|
positiveButtonText: strings.okay()
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const mime = type === "file" ? "*/*" : "image/*";
|
const mime = type === "file" ? "*/*" : "image/*";
|
||||||
const attachments = await insertAttachments(mime);
|
const attachments = await insertAttachments(mime);
|
||||||
const editor = useEditorManager.getState().getEditor(id)?.editor;
|
const editor = useEditorManager.getState().getEditor(id)?.editor;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import {
|
|||||||
import { IEditor, MAX_AUTO_SAVEABLE_WORDS } from "./types";
|
import { IEditor, MAX_AUTO_SAVEABLE_WORDS } from "./types";
|
||||||
import { useEditorConfig, useToolbarConfig, useEditorManager } from "./manager";
|
import { useEditorConfig, useToolbarConfig, useEditorManager } from "./manager";
|
||||||
import { useStore as useSettingsStore } from "../../stores/setting-store";
|
import { useStore as useSettingsStore } from "../../stores/setting-store";
|
||||||
|
import { useStore as useUserStore } from "../../stores/user-store";
|
||||||
import { debounce, useAreFeaturesAvailable } from "@notesnook/common";
|
import { debounce, useAreFeaturesAvailable } from "@notesnook/common";
|
||||||
import { ScopedThemeProvider } from "../theme-provider";
|
import { ScopedThemeProvider } from "../theme-provider";
|
||||||
import { useStore as useThemeStore } from "../../stores/theme-store";
|
import { useStore as useThemeStore } from "../../stores/theme-store";
|
||||||
@@ -65,6 +66,8 @@ import { EDITOR_ZOOM } from "./common";
|
|||||||
import { ScrollContainer } from "@notesnook/ui";
|
import { ScrollContainer } from "@notesnook/ui";
|
||||||
import { showFeatureNotAllowedToast } from "../../common/toasts";
|
import { showFeatureNotAllowedToast } from "../../common/toasts";
|
||||||
import { UpgradeDialog } from "../../dialogs/buy-dialog/upgrade-dialog";
|
import { UpgradeDialog } from "../../dialogs/buy-dialog/upgrade-dialog";
|
||||||
|
import { ConfirmDialog } from "../../dialogs/confirm";
|
||||||
|
import { strings } from "@notesnook/intl";
|
||||||
|
|
||||||
export type OnChangeHandler = (
|
export type OnChangeHandler = (
|
||||||
content: () => string,
|
content: () => string,
|
||||||
@@ -185,7 +188,6 @@ function TipTap(props: TipTapProps) {
|
|||||||
|
|
||||||
const autoSave = useRef(true);
|
const autoSave = useRef(true);
|
||||||
const { toolbarConfig } = useToolbarConfig();
|
const { toolbarConfig } = useToolbarConfig();
|
||||||
|
|
||||||
const features = useAreFeaturesAvailable([
|
const features = useAreFeaturesAvailable([
|
||||||
"callout",
|
"callout",
|
||||||
"outlineList",
|
"outlineList",
|
||||||
@@ -196,9 +198,19 @@ function TipTap(props: TipTapProps) {
|
|||||||
claims: {
|
claims: {
|
||||||
callout: !!features?.callout?.isAllowed,
|
callout: !!features?.callout?.isAllowed,
|
||||||
outlineList: !!features?.outlineList?.isAllowed,
|
outlineList: !!features?.outlineList?.isAllowed,
|
||||||
taskList: !!features?.taskList?.isAllowed
|
taskList: !!features?.taskList?.isAllowed,
|
||||||
|
insertAttachment: !!useUserStore.getState().isLoggedIn
|
||||||
},
|
},
|
||||||
onPermissionDenied: (claim, silent) => {
|
onPermissionDenied: (claim, silent) => {
|
||||||
|
if (claim === "insertAttachment") {
|
||||||
|
ConfirmDialog.show({
|
||||||
|
title: strings.notLoggedIn(),
|
||||||
|
message: strings.loginToUploadAttachments(),
|
||||||
|
positiveButtonText: strings.okay()
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (silent) {
|
if (silent) {
|
||||||
console.log(features, features?.[claim]);
|
console.log(features, features?.[claim]);
|
||||||
if (features?.[claim]) showFeatureNotAllowedToast(features[claim]);
|
if (features?.[claim]) showFeatureNotAllowedToast(features[claim]);
|
||||||
|
|||||||
8
docs/help/contents/faqs/login-to-upload-attachments.md
Normal file
8
docs/help/contents/faqs/login-to-upload-attachments.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
title: Login to upload attachments
|
||||||
|
description: We require users to be logged in to upload attachments.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Login to upload attachments
|
||||||
|
|
||||||
|
We require users to be logged in to upload attachments. This is because attachments are encrypted using a sub-key derived from your database encryption key. Without a login, we cannot encrypt/upload/sync attachments.
|
||||||
@@ -84,3 +84,4 @@ navigation:
|
|||||||
children:
|
children:
|
||||||
- path: faqs/what-are-merge-conflicts.md
|
- path: faqs/what-are-merge-conflicts.md
|
||||||
- path: faqs/is-there-an-eta.md
|
- path: faqs/is-there-an-eta.md
|
||||||
|
- paht: faqs/login-to-upload-attachments.md
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ const Tiptap = ({
|
|||||||
claims: {
|
claims: {
|
||||||
callout: !!settings.features?.callout?.isAllowed,
|
callout: !!settings.features?.callout?.isAllowed,
|
||||||
outlineList: !!settings.features?.outlineList?.isAllowed,
|
outlineList: !!settings.features?.outlineList?.isAllowed,
|
||||||
taskList: !!settings.features?.taskList?.isAllowed
|
taskList: !!settings.features?.taskList?.isAllowed,
|
||||||
|
insertAttachment: settings.loggedIn
|
||||||
},
|
},
|
||||||
onPermissionDenied: (claim) => {
|
onPermissionDenied: (claim) => {
|
||||||
post(
|
post(
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ const initialState = {
|
|||||||
fontFamily: "sans-serif",
|
fontFamily: "sans-serif",
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
timeFormat: "12-hour",
|
timeFormat: "12-hour",
|
||||||
dateFormat: "DD-MM-YYYY"
|
dateFormat: "DD-MM-YYYY",
|
||||||
|
loggedIn: false
|
||||||
};
|
};
|
||||||
|
|
||||||
global.settingsController = {
|
global.settingsController = {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ export type Settings = {
|
|||||||
fontScale: number;
|
fontScale: number;
|
||||||
markdownShortcuts: boolean;
|
markdownShortcuts: boolean;
|
||||||
features: Record<any, any>;
|
features: Record<any, any>;
|
||||||
|
loggedIn: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* eslint-disable no-var */
|
/* eslint-disable no-var */
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { createNodeView } from "../react/index.js";
|
|||||||
import { AttachmentComponent } from "./component.js";
|
import { AttachmentComponent } from "./component.js";
|
||||||
import { Attachment } from "./types.js";
|
import { Attachment } from "./types.js";
|
||||||
import { tiptapKeys } from "@notesnook/common";
|
import { tiptapKeys } from "@notesnook/common";
|
||||||
|
import { hasPermission } from "../../types.js";
|
||||||
|
|
||||||
export type AttachmentType = "image" | "file" | "camera";
|
export type AttachmentType = "image" | "file" | "camera";
|
||||||
export interface AttachmentOptions {
|
export interface AttachmentOptions {
|
||||||
@@ -110,6 +111,10 @@ export const AttachmentNode = Node.create<AttachmentOptions>({
|
|||||||
insertAttachment:
|
insertAttachment:
|
||||||
(attachment) =>
|
(attachment) =>
|
||||||
({ commands, state }) => {
|
({ commands, state }) => {
|
||||||
|
if (!hasPermission("insertAttachment")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const { $from } = state.selection;
|
const { $from } = state.selection;
|
||||||
const maybeAttachmentNode = state.doc.nodeAt($from.pos);
|
const maybeAttachmentNode = state.doc.nodeAt($from.pos);
|
||||||
if (maybeAttachmentNode?.type === this.type) {
|
if (maybeAttachmentNode?.type === this.type) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import { createNodeView } from "../react/index.js";
|
|||||||
import { TextDirections } from "../text-direction/index.js";
|
import { TextDirections } from "../text-direction/index.js";
|
||||||
import { ImageComponent } from "./component.js";
|
import { ImageComponent } from "./component.js";
|
||||||
import { tiptapKeys } from "@notesnook/common";
|
import { tiptapKeys } from "@notesnook/common";
|
||||||
import { DOMParser } from "@tiptap/pm/model";
|
import { hasPermission } from "../../types.js";
|
||||||
|
|
||||||
export interface ImageOptions {
|
export interface ImageOptions {
|
||||||
inline: boolean;
|
inline: boolean;
|
||||||
@@ -159,6 +159,10 @@ export const ImageNode = Node.create<ImageOptions>({
|
|||||||
insertImage:
|
insertImage:
|
||||||
(options) =>
|
(options) =>
|
||||||
({ commands, state }) => {
|
({ commands, state }) => {
|
||||||
|
if (!hasPermission("insertAttachment")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const { $from } = state.selection;
|
const { $from } = state.selection;
|
||||||
const maybeImageNode = state.doc.nodeAt($from.pos);
|
const maybeImageNode = state.doc.nodeAt($from.pos);
|
||||||
if (maybeImageNode?.type === this.type) {
|
if (maybeImageNode?.type === this.type) {
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export type PermissionHandlerOptions = {
|
|||||||
const ClaimsMap = {
|
const ClaimsMap = {
|
||||||
callout: ["setCallout"] as (keyof UnionCommands)[],
|
callout: ["setCallout"] as (keyof UnionCommands)[],
|
||||||
outlineList: ["toggleOutlineList"] as (keyof UnionCommands)[],
|
outlineList: ["toggleOutlineList"] as (keyof UnionCommands)[],
|
||||||
taskList: ["toggleTaskList"] as (keyof UnionCommands)[]
|
taskList: ["toggleTaskList"] as (keyof UnionCommands)[],
|
||||||
|
insertAttachment: ["insertAttachment"] as (keyof UnionCommands)[]
|
||||||
};
|
};
|
||||||
|
|
||||||
export function usePermissionHandler(options: PermissionHandlerOptions) {
|
export function usePermissionHandler(options: PermissionHandlerOptions) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { Popup } from "../components/popup.js";
|
|||||||
import { downloadImage, toDataURL } from "../../utils/downloader.js";
|
import { downloadImage, toDataURL } from "../../utils/downloader.js";
|
||||||
import { useToolbarStore } from "../stores/toolbar-store.js";
|
import { useToolbarStore } from "../stores/toolbar-store.js";
|
||||||
import { strings } from "@notesnook/intl";
|
import { strings } from "@notesnook/intl";
|
||||||
|
import { hasPermission } from "../../types.js";
|
||||||
|
|
||||||
export type ImageUploadPopupProps = {
|
export type ImageUploadPopupProps = {
|
||||||
onInsert: (image: Partial<ImageAttributes>) => void;
|
onInsert: (image: Partial<ImageAttributes>) => void;
|
||||||
@@ -46,6 +47,10 @@ export function ImageUploadPopup(props: ImageUploadPopupProps) {
|
|||||||
title: strings.insert(),
|
title: strings.insert(),
|
||||||
disabled: !url,
|
disabled: !url,
|
||||||
onClick: async () => {
|
onClick: async () => {
|
||||||
|
if (!hasPermission("insertAttachment")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
setIsDownloading(true);
|
setIsDownloading(true);
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
|
|
||||||
|
|||||||
@@ -3699,6 +3699,10 @@ msgstr "Login successful"
|
|||||||
msgid "Login to encrypt and sync notes"
|
msgid "Login to encrypt and sync notes"
|
||||||
msgstr "Login to encrypt and sync notes"
|
msgstr "Login to encrypt and sync notes"
|
||||||
|
|
||||||
|
#: src/strings.ts:2608
|
||||||
|
msgid "Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)"
|
||||||
|
msgstr "Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)"
|
||||||
|
|
||||||
#: src/strings.ts:541
|
#: src/strings.ts:541
|
||||||
msgid "Login to your account"
|
msgid "Login to your account"
|
||||||
msgstr "Login to your account"
|
msgstr "Login to your account"
|
||||||
|
|||||||
@@ -3679,6 +3679,10 @@ msgstr ""
|
|||||||
msgid "Login to encrypt and sync notes"
|
msgid "Login to encrypt and sync notes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/strings.ts:2608
|
||||||
|
msgid "Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/strings.ts:541
|
#: src/strings.ts:541
|
||||||
msgid "Login to your account"
|
msgid "Login to your account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -2603,5 +2603,7 @@ Use this if changes from other devices are not appearing on this device. This wi
|
|||||||
finishPurchaseInBrowser: () => t`Finish your purchase in the browser.`,
|
finishPurchaseInBrowser: () => t`Finish your purchase in the browser.`,
|
||||||
goBack: () => t`Go back`,
|
goBack: () => t`Go back`,
|
||||||
clickToDirectlyClaimPromo: () =>
|
clickToDirectlyClaimPromo: () =>
|
||||||
t`Click here to directly claim the promotion.`
|
t`Click here to directly claim the promotion.`,
|
||||||
|
loginToUploadAttachments: () =>
|
||||||
|
t`Login to upload attachments. [Read more](https://help.notesnook.com/faqs/login-to-upload-attachments)`
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user