dropbox should use sub folder

This commit is contained in:
fyears 2021-12-01 00:33:24 +08:00
parent e9e9e2b6eb
commit 2e800af4f8
3 changed files with 77 additions and 21 deletions

View File

@ -110,6 +110,7 @@ export default class RemotelySavePlugin extends Plugin {
this.settings.s3, this.settings.s3,
this.settings.webdav, this.settings.webdav,
this.settings.dropbox, this.settings.dropbox,
this.app.vault.getName(),
() => self.saveSettings() () => self.saveSettings()
); );
const remoteRsp = await client.listFromRemote(); const remoteRsp = await client.listFromRemote();
@ -349,6 +350,7 @@ export class DropboxAuthModal extends Modal {
undefined, undefined,
undefined, undefined,
this.plugin.settings.dropbox, this.plugin.settings.dropbox,
this.app.vault.getName(),
() => self.plugin.saveSettings() () => self.plugin.saveSettings()
); );
const username = await client.getUser(); const username = await client.getUser();
@ -626,6 +628,7 @@ class RemotelySaveSettingTab extends PluginSettingTab {
undefined, undefined,
undefined, undefined,
this.plugin.settings.dropbox, this.plugin.settings.dropbox,
this.app.vault.getName(),
() => self.plugin.saveSettings() () => self.plugin.saveSettings()
); );
await client.revokeAuth(); await client.revokeAuth();
@ -687,6 +690,7 @@ class RemotelySaveSettingTab extends PluginSettingTab {
undefined, undefined,
undefined, undefined,
this.plugin.settings.dropbox, this.plugin.settings.dropbox,
this.app.vault.getName(),
() => self.plugin.saveSettings() () => self.plugin.saveSettings()
); );

View File

@ -19,6 +19,7 @@ export class RemoteClient {
s3Config?: s3.S3Config, s3Config?: s3.S3Config,
webdavConfig?: webdav.WebdavConfig, webdavConfig?: webdav.WebdavConfig,
dropboxConfig?: dropbox.DropboxConfig, dropboxConfig?: dropbox.DropboxConfig,
vaultName?: string,
saveUpdatedConfigFunc?: () => Promise<any> saveUpdatedConfigFunc?: () => Promise<any>
) { ) {
this.serviceType = serviceType; this.serviceType = serviceType;
@ -31,12 +32,15 @@ export class RemoteClient {
this.webdavConfig = webdavConfig; this.webdavConfig = webdavConfig;
this.webdavClient = webdav.getWebdavClient(this.webdavConfig); this.webdavClient = webdav.getWebdavClient(this.webdavConfig);
} else if (serviceType === "dropbox") { } else if (serviceType === "dropbox") {
if (saveUpdatedConfigFunc === undefined) { if (vaultName === undefined || saveUpdatedConfigFunc === undefined) {
throw Error("remember to provide callback while init dropbox client"); throw Error(
"remember to provide vault name and callback while init dropbox client"
);
} }
this.dropboxConfig = dropboxConfig; this.dropboxConfig = dropboxConfig;
this.dropboxClient = dropbox.getDropboxClient( this.dropboxClient = dropbox.getDropboxClient(
this.dropboxConfig, this.dropboxConfig,
vaultName,
saveUpdatedConfigFunc saveUpdatedConfigFunc
); );
} else { } else {

View File

@ -37,10 +37,11 @@ export const DEFAULT_DROPBOX_CONFIG = {
username: "", username: "",
}; };
export const getDropboxPath = (fileOrFolderPath: string) => { export const getDropboxPath = (fileOrFolderPath: string, vaultName: string) => {
let key = fileOrFolderPath; let key = fileOrFolderPath;
if (!fileOrFolderPath.startsWith("/")) { if (!fileOrFolderPath.startsWith("/")) {
key = `/${fileOrFolderPath}`; // then this is original path in Obsidian
key = `/${vaultName}/${fileOrFolderPath}`;
} }
if (key.endsWith("/")) { if (key.endsWith("/")) {
key = key.slice(0, key.length - 1); key = key.slice(0, key.length - 1);
@ -48,20 +49,26 @@ export const getDropboxPath = (fileOrFolderPath: string) => {
return key; return key;
}; };
const getNormPath = (fileOrFolderPath: string) => { const getNormPath = (fileOrFolderPath: string, vaultName: string) => {
if (fileOrFolderPath.startsWith("/")) { if (
return fileOrFolderPath.slice(1); !(
fileOrFolderPath === `/${vaultName}` ||
fileOrFolderPath.startsWith(`/${vaultName}/`)
)
) {
throw Error(`"${fileOrFolderPath}" doesn't starts with "/${vaultName}/"`);
} }
return fileOrFolderPath; return fileOrFolderPath.slice(`/${vaultName}/`.length);
}; };
const fromDropboxItemToRemoteItem = ( const fromDropboxItemToRemoteItem = (
x: x:
| files.FileMetadataReference | files.FileMetadataReference
| files.FolderMetadataReference | files.FolderMetadataReference
| files.DeletedMetadataReference | files.DeletedMetadataReference,
vaultName: string
): RemoteItem => { ): RemoteItem => {
let key = getNormPath(x.path_display); let key = getNormPath(x.path_display, vaultName);
if (x[".tag"] === "folder" && !key.endsWith("/")) { if (x[".tag"] === "folder" && !key.endsWith("/")) {
key = `${key}/`; key = `${key}/`;
} }
@ -261,17 +268,23 @@ export const setConfigBySuccessfullAuthInplace = async (
export class WrappedDropboxClient { export class WrappedDropboxClient {
dropboxConfig: DropboxConfig; dropboxConfig: DropboxConfig;
vaultName: string;
saveUpdatedConfigFunc: () => Promise<any>; saveUpdatedConfigFunc: () => Promise<any>;
dropbox: Dropbox; dropbox: Dropbox;
vaultFolderExists: boolean;
constructor( constructor(
dropboxConfig: DropboxConfig, dropboxConfig: DropboxConfig,
vaultName: string,
saveUpdatedConfigFunc: () => Promise<any> saveUpdatedConfigFunc: () => Promise<any>
) { ) {
this.dropboxConfig = dropboxConfig; this.dropboxConfig = dropboxConfig;
this.vaultName = vaultName;
this.saveUpdatedConfigFunc = saveUpdatedConfigFunc; this.saveUpdatedConfigFunc = saveUpdatedConfigFunc;
this.vaultFolderExists = false;
} }
init = async () => { init = async () => {
// check token
if ( if (
this.dropboxConfig.accessToken === "" || this.dropboxConfig.accessToken === "" ||
this.dropboxConfig.refreshToken === "" this.dropboxConfig.refreshToken === ""
@ -303,6 +316,33 @@ export class WrappedDropboxClient {
accessToken: this.dropboxConfig.accessToken, accessToken: this.dropboxConfig.accessToken,
}); });
} }
// check vault folder
// console.log(`checking remote has folder /${this.vaultName}`);
if (this.vaultFolderExists) {
// console.log(`already checked, /${this.vaultName} exist before`)
} else {
const res = await this.dropbox.filesListFolder({
path: "",
recursive: false,
});
for (const item of res.result.entries) {
if (item.path_display === `/${this.vaultName}`) {
this.vaultFolderExists = true;
break;
}
}
if (!this.vaultFolderExists) {
console.log(`remote does not have folder /${this.vaultName}`);
await this.dropbox.filesCreateFolderV2({
path: `/${this.vaultName}`,
});
console.log(`remote folder /${this.vaultName} created`);
} else {
// console.log(`remote folder /${this.vaultName} exists`);
}
}
return this.dropbox; return this.dropbox;
}; };
} }
@ -313,9 +353,14 @@ export class WrappedDropboxClient {
*/ */
export const getDropboxClient = ( export const getDropboxClient = (
dropboxConfig: DropboxConfig, dropboxConfig: DropboxConfig,
vaultName: string,
saveUpdatedConfigFunc: () => Promise<any> saveUpdatedConfigFunc: () => Promise<any>
) => { ) => {
return new WrappedDropboxClient(dropboxConfig, saveUpdatedConfigFunc); return new WrappedDropboxClient(
dropboxConfig,
vaultName,
saveUpdatedConfigFunc
);
}; };
export const getRemoteMeta = async ( export const getRemoteMeta = async (
@ -328,7 +373,7 @@ export const getRemoteMeta = async (
// we instead try to list files // we instead try to list files
// if no error occurs, we ensemble a fake result. // if no error occurs, we ensemble a fake result.
const rsp = await client.dropbox.filesListFolder({ const rsp = await client.dropbox.filesListFolder({
path: "", path: `/${client.vaultName}`,
recursive: false, // don't need to recursive here recursive: false, // don't need to recursive here
}); });
if (rsp.status !== 200) { if (rsp.status !== 200) {
@ -343,7 +388,7 @@ export const getRemoteMeta = async (
} as RemoteItem; } as RemoteItem;
} }
const key = getDropboxPath(fileOrFolderPath); const key = getDropboxPath(fileOrFolderPath, client.vaultName);
const rsp = await client.dropbox.filesGetMetadata({ const rsp = await client.dropbox.filesGetMetadata({
path: key, path: key,
@ -351,7 +396,7 @@ export const getRemoteMeta = async (
if (rsp.status !== 200) { if (rsp.status !== 200) {
throw Error(JSON.stringify(rsp)); throw Error(JSON.stringify(rsp));
} }
return fromDropboxItemToRemoteItem(rsp.result); return fromDropboxItemToRemoteItem(rsp.result, client.vaultName);
}; };
export const uploadToRemote = async ( export const uploadToRemote = async (
@ -369,7 +414,7 @@ export const uploadToRemote = async (
if (password !== "") { if (password !== "") {
uploadFile = remoteEncryptedKey; uploadFile = remoteEncryptedKey;
} }
uploadFile = getDropboxPath(uploadFile); uploadFile = getDropboxPath(uploadFile, client.vaultName);
const isFolder = fileOrFolderPath.endsWith("/"); const isFolder = fileOrFolderPath.endsWith("/");
@ -425,7 +470,9 @@ export const uploadToRemote = async (
}); });
// we want to mark that parent folders are created // we want to mark that parent folders are created
if (foldersCreatedBefore !== undefined) { if (foldersCreatedBefore !== undefined) {
const dirs = getFolderLevels(uploadFile).map(getDropboxPath); const dirs = getFolderLevels(uploadFile).map((x) =>
getDropboxPath(x, client.vaultName)
);
for (const dir of dirs) { for (const dir of dirs) {
foldersCreatedBefore?.add(dir); foldersCreatedBefore?.add(dir);
} }
@ -443,7 +490,7 @@ export const listFromRemote = async (
} }
await client.init(); await client.init();
const res = await client.dropbox.filesListFolder({ const res = await client.dropbox.filesListFolder({
path: "", path: `/${client.vaultName}`,
recursive: true, recursive: true,
}); });
if (res.status !== 200) { if (res.status !== 200) {
@ -453,7 +500,8 @@ export const listFromRemote = async (
const contents = res.result.entries; const contents = res.result.entries;
const unifiedContents = contents const unifiedContents = contents
.filter((x) => x[".tag"] !== "deleted") .filter((x) => x[".tag"] !== "deleted")
.map(fromDropboxItemToRemoteItem); .filter((x) => x.path_display !== `/${client.vaultName}`)
.map((x) => fromDropboxItemToRemoteItem(x, client.vaultName));
fixLastModifiedTimeInplace(unifiedContents); fixLastModifiedTimeInplace(unifiedContents);
return { return {
Contents: unifiedContents, Contents: unifiedContents,
@ -465,7 +513,7 @@ const downloadFromRemoteRaw = async (
fileOrFolderPath: string fileOrFolderPath: string
) => { ) => {
await client.init(); await client.init();
const key = getDropboxPath(fileOrFolderPath); const key = getDropboxPath(fileOrFolderPath, client.vaultName);
const rsp = await client.dropbox.filesDownload({ const rsp = await client.dropbox.filesDownload({
path: key, path: key,
}); });
@ -505,7 +553,7 @@ export const downloadFromRemote = async (
if (password !== "") { if (password !== "") {
downloadFile = remoteEncryptedKey; downloadFile = remoteEncryptedKey;
} }
downloadFile = getDropboxPath(downloadFile); downloadFile = getDropboxPath(downloadFile, client.vaultName);
const remoteContent = await downloadFromRemoteRaw(client, downloadFile); const remoteContent = await downloadFromRemoteRaw(client, downloadFile);
let localContent = remoteContent; let localContent = remoteContent;
if (password !== "") { if (password !== "") {
@ -530,7 +578,7 @@ export const deleteFromRemote = async (
if (password !== "") { if (password !== "") {
remoteFileName = remoteEncryptedKey; remoteFileName = remoteEncryptedKey;
} }
remoteFileName = getDropboxPath(remoteFileName); remoteFileName = getDropboxPath(remoteFileName, client.vaultName);
await client.init(); await client.init();
try { try {