From 586e587d96146f301f49cd127891a4231a71eb52 Mon Sep 17 00:00:00 2001 From: fyears <1142836+fyears@users.noreply.github.com> Date: Sat, 6 Jan 2024 17:21:53 +0800 Subject: [PATCH] partial of s3 remoteprefix --- src/baseTypes.ts | 1 + src/langs/en.json | 9 ++++ src/langs/zh_cn.json | 9 ++++ src/langs/zh_tw.json | 9 ++++ src/main.ts | 3 ++ src/remoteForS3.ts | 19 ++++++++ src/settings.ts | 106 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 156 insertions(+) diff --git a/src/baseTypes.ts b/src/baseTypes.ts index cfb1bfc..893dfe8 100644 --- a/src/baseTypes.ts +++ b/src/baseTypes.ts @@ -24,6 +24,7 @@ export interface S3Config { bypassCorsLocally?: boolean; partsConcurrency?: number; forcePathStyle?: boolean; + remotePrefix?: string; } export interface DropboxConfig { diff --git a/src/langs/en.json b/src/langs/en.json index 4c382fe..1cd04b3 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -67,6 +67,13 @@ "modal_remotebasedir_secondconfirm_vaultname": "Reset To The Default Vault Folder Name", "modal_remotebasedir_secondconfirm_change": "Confirm To Change", "modal_remotebasedir_notice": "New remote base directory config saved!", + "modal_remoteprefix_title": "You are changing the remote prefix config", + "modal_remoteprefix_shortdesc": "1. The plugin would NOT automatically move the content from the old directory to the new one directly on the remote. Everything syncs from the beginning again.\n2. If you set the string to the empty, the prefix will be empty and the files will be saved at the root of the bucket.\n3. The remote directory name itself would not be encrypted even you've set an E2E password.\n4. Some special char like '?', '/', '\\' are not allowed. Spaces in the beginning or in the end are also trimmed.", + "modal_remoteprefix_invaliddirhint": "Your input contains special characters like '?', '/', '\\' which are not allowed.", + "modal_remoteprefix_tosave": "The prefix to save is {{{prefix}}}", + "modal_remoteprefix_secondconfirm_empty": "The prefix is empty and the files will be saved at the root of the bucket.", + "modal_remoteprefix_secondconfirm_change": "Confirm To Change", + "modal_remoteprefix_notice": "New remote prefix config saved!", "modal_dropboxauth_manualsteps": "Step 1: Visit the address in a browser, and follow the steps.\nStep 2: In the end of the web flow, you obtain a long code. Paste it here then click \"Submit\".", "modal_dropboxauth_autosteps": "Visit the address in a browser, and follow the steps.\nFinally you should be redirected to Obsidian.", "modal_dropboxauth_copybutton": "Click to copy the auth url", @@ -140,6 +147,8 @@ "settings_checkonnectivity_checking": "Checking...", "settings_remotebasedir": "Change The Remote Base Directory (experimental)", "settings_remotebasedir_desc": "By default the content is synced to a remote directory with the same name as the vault name. You can change the remote folder name here, or keep the input field empty to reset to the default. You need to click \"Confirm\".", + "settings_remoteprefix": "Change The Remote Prefix (experimental)", + "settings_remoteprefix_desc": "By default in s3 the files are saved at the root of the bucket. You can change the remote prefix here, or keep the input field empty to reset to the default. You need to click \"Confirm\".", "settings_s3": "Remote For S3 or compatible", "settings_s3_disclaimer1": "Disclaimer: This plugin is NOT an official Amazon product.", "settings_s3_disclaimer2": "Disclaimer: The information is stored locally. Other malicious/harmful/faulty plugins could read the info. If you see any unintentional access to your bucket, please immediately delete the access key on your AWS (or other S3-service provider) settings.", diff --git a/src/langs/zh_cn.json b/src/langs/zh_cn.json index 2354a18..d0c44e3 100644 --- a/src/langs/zh_cn.json +++ b/src/langs/zh_cn.json @@ -67,6 +67,13 @@ "modal_remotebasedir_secondconfirm_vaultname": "重设回默认的库文件夹名", "modal_remotebasedir_secondconfirm_change": "确认修改", "modal_remotebasedir_notice": "新的远端基文件夹设置已保存!", + "modal_remoteprefix_title": "您正在修改远端路径前缀设置", + "modal_remoteprefix_shortdesc": "1. 本插件并不会自动在远端把内容从旧文件夹移动到新文件夹。所有内容都会重新同步。\n2. 如果你使得文本输入框为空,那么本设置为保存为空,文件将会被存储在桶(Bucket)的根目录。\n3. 即使您设置了端对端加密的密码,远端文件夹名称本身也不会被加密。\n4. 某些特殊字符,如“?”、“/”、“\\”是不允许的。文本前后的空格也会被自动删去。", + "modal_remoteprefix_invaliddirhint": "您所输入的内容含有某些特殊字符,如“?”、“/”、“\\”,它们是不允许的。", + "modal_remoteprefix_tosave": "您设定的新前缀为:“{{{prefix}}}”", + "modal_remoteprefix_secondconfirm_empty": "前缀为空,文件会保存在根目录", + "modal_remoteprefix_secondconfirm_change": "确认修改", + "modal_remoteprefix_notice": "新的远端路径前缀设置已保存!", "modal_dropboxauth_manualsteps": "第 1 步:在浏览器中访问以下地址,然后按照网页提示操作。\n到了最后,您应该会获得一串很长的代码文本,请复制粘贴到下方,并点击“提交”", "modal_dropboxauth_autosteps": "在浏览器中访问以下地址,然后按照网页提示操作。\n到了最后,您应该会被自动重定向回来 Obsidian。", "modal_dropboxauth_copybutton": "点击此按钮从而复制鉴权 url", @@ -140,6 +147,8 @@ "settings_checkonnectivity_checking": "正在检查……", "settings_remotebasedir": "修改远端基文件夹(实验性质)", "settings_remotebasedir_desc": "默认设定,内容会被同步到远端的和资料库同名的文件夹下。您可以在此修改远端文件夹名,或删除输入框文本从而重设到默认值。您需要点击“确认”。", + "settings_remoteprefix": "修改远端前缀路径(实验性质)", + "settings_remoteprefix_desc": "默认设定 s3 保存在存储桶(Bucket)的根目录。您可以在这里修改路径前缀,或者保持为空保持默认设置。您需要点击“确认”。", "settings_s3": "S3 或兼容 S3 的服务的设置", "settings_s3_disclaimer1": "声明:本插件不是 Amazon 的官方产品。", "settings_s3_disclaimer2": "声明:您所输入的信息存储于本地。其它有害的或者出错的插件,是有可能读取到这些信息的。如果您发现了存储桶有不符合预期的访问,请立刻从 AWS(或其它 S3 服务商)删除记录于此的 access key。", diff --git a/src/langs/zh_tw.json b/src/langs/zh_tw.json index 01421a3..2b2393c 100644 --- a/src/langs/zh_tw.json +++ b/src/langs/zh_tw.json @@ -67,6 +67,13 @@ "modal_remotebasedir_secondconfirm_vaultname": "重設回預設的庫資料夾名", "modal_remotebasedir_secondconfirm_change": "確認修改", "modal_remotebasedir_notice": "新的遠端基資料夾設定已儲存!", + "modal_remoteprefix_title": "您正在修改遠端路徑字首設定", + "modal_remoteprefix_shortdesc": "1. 本外掛並不會自動在遠端把內容從舊資料夾移動到新資料夾。所有內容都會重新同步。\n2. 如果你使得文字輸入框為空,那麼本設定為儲存為空,檔案將會被儲存在桶(Bucket)的根目錄。\n3. 即使您設定了端對端加密的密碼,遠端資料夾名稱本身也不會被加密。\n4. 某些特殊字元,如“?”、“/”、“\\”是不允許的。文字前後的空格也會被自動刪去。", + "modal_remoteprefix_invaliddirhint": "您所輸入的內容含有某些特殊字元,如“?”、“/”、“\\”,它們是不允許的。", + "modal_remoteprefix_tosave": "您設定的新字首為:“{{{prefix}}}”", + "modal_remoteprefix_secondconfirm_empty": "字首為空,檔案會儲存在根目錄", + "modal_remoteprefix_secondconfirm_change": "確認修改", + "modal_remoteprefix_notice": "新的遠端路徑字首設定已儲存!", "modal_dropboxauth_manualsteps": "第 1 步:在瀏覽器中訪問以下地址,然後按照網頁提示操作。\n到了最後,您應該會獲得一串很長的程式碼文字,請複製貼上到下方,並點選“提交”", "modal_dropboxauth_autosteps": "在瀏覽器中訪問以下地址,然後按照網頁提示操作。\n到了最後,您應該會被自動重定向回來 Obsidian。", "modal_dropboxauth_copybutton": "點選此按鈕從而複製鑑權 url", @@ -140,6 +147,8 @@ "settings_checkonnectivity_checking": "正在檢查……", "settings_remotebasedir": "修改遠端基資料夾(實驗性質)", "settings_remotebasedir_desc": "預設設定,內容會被同步到遠端的和資料庫同名的資料夾下。您可以在此修改遠端資料夾名,或刪除輸入框文字從而重設到預設值。您需要點選“確認”。", + "settings_remoteprefix": "修改遠端字首路徑(實驗性質)", + "settings_remoteprefix_desc": "預設設定 s3 儲存在儲存桶(Bucket)的根目錄。您可以在這裡修改路徑字首,或者保持為空保持預設設定。您需要點選“確認”。", "settings_s3": "S3 或相容 S3 的服務的設定", "settings_s3_disclaimer1": "宣告:本外掛不是 Amazon 的官方產品。", "settings_s3_disclaimer2": "宣告:您所輸入的資訊儲存於本地。其它有害的或者出錯的外掛,是有可能讀取到這些資訊的。如果您發現了儲存桶有不符合預期的訪問,請立刻從 AWS(或其它 S3 服務商)刪除記錄於此的 access key。", diff --git a/src/main.ts b/src/main.ts index 204d9a9..702f83f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -866,6 +866,9 @@ export default class RemotelySavePlugin extends Plugin { if (this.settings.s3.forcePathStyle === undefined) { this.settings.s3.forcePathStyle = false; } + if (this.settings.s3.remotePrefix === undefined) { + this.settings.s3.remotePrefix = ""; + } if (this.settings.ignorePaths === undefined) { this.settings.ignorePaths = []; } diff --git a/src/remoteForS3.ts b/src/remoteForS3.ts index ddee612..7a33d0a 100644 --- a/src/remoteForS3.ts +++ b/src/remoteForS3.ts @@ -24,6 +24,7 @@ import { Buffer } from "buffer"; import * as mime from "mime-types"; import { Vault, requestUrl, RequestUrlParam } from "obsidian"; import { Readable } from "stream"; +import * as path from "path"; import AggregateError from "aggregate-error"; import { DEFAULT_CONTENT_TYPE, @@ -163,10 +164,28 @@ export const DEFAULT_S3_CONFIG = { bypassCorsLocally: true, partsConcurrency: 20, forcePathStyle: false, + remotePrefix: "", }; export type S3ObjectType = _Object; +export const simpleTransRemotePrefix = (x: string) => { + if (x === undefined) { + return ""; + } + let y = path.posix.normalize(x.trim()); + if (y === undefined || y === "" || y === "/") { + return ""; + } + if (y.startsWith("/")) { + y = y.slice(1); + } + if (!y.endsWith("/")) { + y = `${y}/`; + } + return y; +}; + const fromS3ObjectToRemoteItem = (x: S3ObjectType) => { return { key: x.Key, diff --git a/src/settings.ts b/src/settings.ts index d14381f..afc6ffc 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -54,6 +54,7 @@ import { log, restoreLogWritterInplace, } from "./moreOnLog"; +import { simpleTransRemotePrefix } from "./remoteForS3"; class PasswordModal extends Modal { plugin: RemotelySavePlugin; @@ -219,6 +220,88 @@ class ChangeRemoteBaseDirModal extends Modal { } } +/** + * s3 is special and do not necessarily the same as others + * thus a new Modal here + */ +class ChangeRemotePrefixModal extends Modal { + readonly plugin: RemotelySavePlugin; + readonly newRemotePrefix: string; + constructor(app: App, plugin: RemotelySavePlugin, newRemotePrefix: string) { + super(app); + this.plugin = plugin; + this.newRemotePrefix = newRemotePrefix; + } + + onOpen() { + let { contentEl } = this; + + const t = (x: TransItemType, vars?: any) => { + return this.plugin.i18n.t(x, vars); + }; + + contentEl.createEl("h2", { text: t("modal_remoteprefix_title") }); + t("modal_remoteprefix_shortdesc") + .split("\n") + .forEach((val, idx) => { + contentEl.createEl("p", { + text: val, + }); + }); + + contentEl.createEl("p", { + text: t("modal_remoteprefix_tosave", { prefix: this.newRemotePrefix }), + }); + + if ( + this.newRemotePrefix === "" || + this.newRemotePrefix === this.app.vault.getName() + ) { + new Setting(contentEl) + .addButton((button) => { + button.setButtonText(t("modal_remoteprefix_secondconfirm_empty")); + button.onClick(async () => { + // in the settings, the value is reset to the special case "" + this.plugin.settings.s3.remotePrefix = ""; + await this.plugin.saveSettings(); + new Notice(t("modal_remoteprefix_notice")); + this.close(); + }); + button.setClass("remoteprefix-second-confirm"); + }) + .addButton((button) => { + button.setButtonText(t("goback")); + button.onClick(() => { + this.close(); + }); + }); + } else { + new Setting(contentEl) + .addButton((button) => { + button.setButtonText(t("modal_remoteprefix_secondconfirm_change")); + button.onClick(async () => { + this.plugin.settings.s3.remotePrefix = this.newRemotePrefix; + await this.plugin.saveSettings(); + new Notice(t("modal_remoteprefix_notice")); + this.close(); + }); + button.setClass("remoteprefix-second-confirm"); + }) + .addButton((button) => { + button.setButtonText(t("goback")); + button.onClick(() => { + this.close(); + }); + }); + } + } + + onClose() { + let { contentEl } = this; + contentEl.empty(); + } +} + class DropboxAuthModal extends Modal { readonly plugin: RemotelySavePlugin; readonly authDiv: HTMLDivElement; @@ -867,6 +950,29 @@ export class RemotelySaveSettingTab extends PluginSettingTab { }); }); + let newS3RemotePrefix = this.plugin.settings.s3.remotePrefix || ""; + new Setting(s3Div) + .setName(t("settings_remoteprefix")) + .setDesc(t("settings_remoteprefix_desc")) + .addText((text) => + text + .setPlaceholder("") + .setValue(newS3RemotePrefix) + .onChange((value) => { + newS3RemotePrefix = simpleTransRemotePrefix(value.trim()); + }) + ) + .addButton((button) => { + button.setButtonText(t("confirm")); + button.onClick(() => { + new ChangeRemotePrefixModal( + this.app, + this.plugin, + simpleTransRemotePrefix(newS3RemotePrefix.trim()) + ).open(); + }); + }); + new Setting(s3Div) .setName(t("settings_checkonnectivity")) .setDesc(t("settings_checkonnectivity_desc"))