diff --git a/src/main/server/file.ts b/src/main/server/file.ts index 1ef76ca7..b19420b7 100644 --- a/src/main/server/file.ts +++ b/src/main/server/file.ts @@ -248,9 +248,33 @@ export async function checkHash (repo: string, p: string, oldHash: string) { return oldHash === await hash(repo, p) } -export async function upload (repo: string, buffer: Buffer, path: string) { +export async function upload (repo: string, buffer: Buffer, filePath: string, ifExists: 'rename' | 'overwrite' | 'skip' | 'error' = 'error'): Promise<{ path: string, hash: string }> { if (readonly) throw new Error('Readonly') - await write(repo, path, buffer) + + let newFilePath = filePath + + if (await exists(repo, filePath)) { + if (ifExists === 'overwrite') { + // do nothing + } else if (ifExists === 'skip') { + return { path: filePath, hash: await hash(repo, filePath) } + } else if (ifExists === 'rename') { + const dir = path.dirname(filePath) + const ext = path.extname(filePath) + const base = path.basename(filePath, ext) + + let i = 1 + while (await exists(repo, newFilePath)) { + i++ + const seq = i > 100 ? Math.floor(Math.random() * 1000000) : i + newFilePath = path.join(dir, base + `-${seq}` + ext) + } + } else { + throw new Error('File exists') + } + } + + return { path: newFilePath, hash: await write(repo, newFilePath, buffer) } } function getRelativePath (from: string, to: string) { diff --git a/src/main/server/index.ts b/src/main/server/index.ts index 0825e7cd..5851e11f 100644 --- a/src/main/server/index.ts +++ b/src/main/server/index.ts @@ -206,9 +206,10 @@ const attachment = async (ctx: any, next: any) => { const path = ctx.request.body.path const repo = ctx.request.body.repo const attachment = ctx.request.body.attachment + const exists = ctx.request.body.exists const buffer = Buffer.from(attachment.substring(attachment.indexOf(',') + 1), 'base64') - await file.upload(repo, buffer, path) - ctx.body = result('ok', 'success', path) + const res = await file.upload(repo, buffer, path, exists) + ctx.body = result('ok', 'success', res) } else if (ctx.method === 'GET') { let { repo, path } = ctx.query diff --git a/src/renderer/services/base.ts b/src/renderer/services/base.ts index a0ddcc56..0c1a6578 100644 --- a/src/renderer/services/base.ts +++ b/src/renderer/services/base.ts @@ -48,7 +48,7 @@ export function getAttachmentURL (doc: Doc, opts: { origin: boolean } = { origin * @param name filename * @returns */ -export async function upload (file: File, belongDoc: Pick, name?: string) { +export async function upload (file: File, belongDoc: Pick, name?: string, ifExists: 'rename' | 'overwrite' | 'skip' | 'error' = 'rename'): Promise { if (FLAG_DEMO) { return Promise.resolve(URL.createObjectURL(file)) } @@ -67,11 +67,13 @@ export async function upload (file: File, belongDoc: Pick, .replaceAll('{date}', dayjs().format('YYYY-MM-DD')) .replaceAll('{docHash}', binMd5(parentNameWithoutMdExt).slice(0, 8)) - const path: string = resolve(parentPath, assetsDir, filename) + let path: string = resolve(parentPath, assetsDir, filename) logger.debug('upload', belongDoc, file, path) - await api.upload(belongDoc.repo, fileBase64Url, path) + const res = await api.upload(belongDoc.repo, fileBase64Url, path, ifExists) + + path = res.data.path if ( assetsPathType === 'relative' || diff --git a/src/renderer/support/api.ts b/src/renderer/support/api.ts index 22d97987..b606778f 100644 --- a/src/renderer/support/api.ts +++ b/src/renderer/support/api.ts @@ -393,12 +393,14 @@ export async function watchFs ( * @param repo * @param fileBase64Url * @param filePath + * @param ifExists */ -export async function upload (repo: string, fileBase64Url: string, filePath: string): Promise> { +export async function upload (repo: string, fileBase64Url: string, filePath: string, ifExists: 'rename' | 'overwrite' | 'skip' | 'error' = 'rename'): Promise> { const formData = new FormData() formData.append('repo', repo) formData.append('path', filePath) formData.append('attachment', fileBase64Url) + formData.append('exists', ifExists) return fetchHttp('/api/attachment', { method: 'POST', body: formData }) }