Reorganize app workspaces and align Admin architecture
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { posix } from 'node:path'
|
||||
|
||||
export interface FileNameMeta {
|
||||
name: string
|
||||
ext: string
|
||||
}
|
||||
|
||||
export interface UniqueNameFormatterParams {
|
||||
base: string
|
||||
count: number
|
||||
extension: string
|
||||
}
|
||||
|
||||
export type UniqueNameFormatter = (params: UniqueNameFormatterParams) => string
|
||||
|
||||
export default class PathService {
|
||||
public toStoragePath(path: string = ''): string {
|
||||
let safePath = path.replace(/^(\.\.(\/|\\|$))+/, '')
|
||||
safePath = safePath.startsWith('/') ? safePath.slice(1) : safePath
|
||||
|
||||
return safePath
|
||||
}
|
||||
|
||||
public toClientPath(path: string = ''): string {
|
||||
return path.replace(/^\/?uploads\//, '/')
|
||||
}
|
||||
|
||||
public join(...parts: string[]): string {
|
||||
return posix.join(...parts)
|
||||
}
|
||||
|
||||
public dirname(path: string): string {
|
||||
return this.toStoragePath(path).split('/').slice(0, -1).join('/')
|
||||
}
|
||||
|
||||
public basename(path: string): string {
|
||||
return path.split('/').reverse()[0]
|
||||
}
|
||||
|
||||
public getFileNameMeta(name: string): FileNameMeta {
|
||||
const extIndex = name.lastIndexOf('.')
|
||||
const rawName = extIndex !== -1 ? name.slice(0, extIndex) : name
|
||||
const ext = extIndex !== -1 ? name.slice(extIndex).trim() : ''
|
||||
|
||||
return {
|
||||
name: rawName,
|
||||
ext,
|
||||
}
|
||||
}
|
||||
|
||||
public sanitizeFileName(name: string): string {
|
||||
return name.replace(/[()]/g, '').replace(/[^a-zA-Z0-9.\-_ ]/g, '')
|
||||
}
|
||||
|
||||
public async generateUniqueName(
|
||||
dir: string,
|
||||
fileName: string,
|
||||
exists: (path: string) => Promise<boolean>,
|
||||
formatter?: UniqueNameFormatter
|
||||
): Promise<string> {
|
||||
const { ext, name } = this.getFileNameMeta(fileName)
|
||||
const safeBase = this.sanitizeFileName(name)
|
||||
|
||||
let counter = 1
|
||||
let newName = `${safeBase}${ext}`
|
||||
|
||||
while (await exists(this.join(dir, newName))) {
|
||||
newName =
|
||||
typeof formatter === 'function'
|
||||
? formatter({ base: safeBase, count: counter, extension: ext })
|
||||
: `${safeBase}-${counter}${ext}`
|
||||
|
||||
counter++
|
||||
|
||||
if (counter > 5) {
|
||||
newName = `${randomUUID()}${ext}`
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return newName
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user