feat(core): Enhanced directory handling and file restoration from trash

This commit is contained in:
Philipp Kunz 2024-11-24 19:56:12 +01:00
parent 8e9041fbbf
commit 154854dc21
5 changed files with 81 additions and 10 deletions

View File

@ -1,5 +1,11 @@
# Changelog # Changelog
## 2024-11-24 - 3.3.0 - feat(core)
Enhanced directory handling and file restoration from trash
- Refined getSubDirectoryByName to handle file paths treated as directories.
- Introduced file restoration function from trash to original or specified paths.
## 2024-11-24 - 3.2.2 - fix(core) ## 2024-11-24 - 3.2.2 - fix(core)
Refactor Bucket class for improved error handling Refactor Bucket class for improved error handling

View File

@ -30,7 +30,7 @@ tap.test('should clean all contents', async () => {
tap.test('should delete a file into the normally', async () => { tap.test('should delete a file into the normally', async () => {
const path = 'trashtest/trashme.txt'; const path = 'trashtest/trashme.txt';
const file = await myBucket.fastPut({ const file = await myBucket.fastPutStrict({
path, path,
contents: 'I\'m in the trash test content!', contents: 'I\'m in the trash test content!',
}); });
@ -44,7 +44,7 @@ tap.test('should delete a file into the normally', async () => {
tap.test('should put a file into the trash', async () => { tap.test('should put a file into the trash', async () => {
const path = 'trashtest/trashme.txt'; const path = 'trashtest/trashme.txt';
const file = await myBucket.fastPut({ const file = await myBucket.fastPutStrict({
path, path,
contents: 'I\'m in the trash test content!', contents: 'I\'m in the trash test content!',
}); });
@ -60,4 +60,19 @@ tap.test('should put a file into the trash', async () => {
}); });
}); });
tap.test('should restore a file from trash', async () => {
const baseDirectory = await myBucket.getBaseDirectory();
const file = await baseDirectory.getFileStrict({
path: 'trashtest/trashme.txt',
getFromTrash: true
});
const trashFileMeta = await file.getMetaData();
const data = await trashFileMeta.getCustomMetaData({
key: 'recycle'
});
expect(file).toBeInstanceOf(smartbucket.File);
await file.restore();
});
export default tap.start(); export default tap.start();

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartbucket', name: '@push.rocks/smartbucket',
version: '3.2.2', version: '3.3.0',
description: 'A TypeScript library offering simple and cloud-agnostic object storage with advanced features like bucket creation, file and directory management, and data streaming.' description: 'A TypeScript library offering simple and cloud-agnostic object storage with advanced features like bucket creation, file and directory management, and data streaming.'
} }

View File

@ -10,9 +10,9 @@ export class Directory {
public parentDirectoryRef: Directory; public parentDirectoryRef: Directory;
public name: string; public name: string;
public tree: string[]; public tree!: string[];
public files: string[]; public files!: string[];
public folders: string[]; public folders!: string[];
constructor(bucketRefArg: Bucket, parentDirectory: Directory, name: string) { constructor(bucketRefArg: Bucket, parentDirectory: Directory, name: string) {
this.bucketRef = bucketRefArg; this.bucketRef = bucketRefArg;
@ -192,9 +192,22 @@ export class Directory {
* gets a sub directory by name * gets a sub directory by name
*/ */
public async getSubDirectoryByName(dirNameArg: string, optionsArg: { public async getSubDirectoryByName(dirNameArg: string, optionsArg: {
/**
* in s3 a directory does not exist if it is empty
* this option returns a directory even if it is empty
*/
getEmptyDirectory?: boolean; getEmptyDirectory?: boolean;
/**
* in s3 a directory does not exist if it is empty
* this option creates a directory even if it is empty using a initializer file
*/
createWithInitializerFile?: boolean; createWithInitializerFile?: boolean;
/**
* if the path is a file path, it will be treated as a file and the parent directory will be returned
*/
couldBeFilePath?: boolean;
} = {}): Promise<Directory | null> { } = {}): Promise<Directory | null> {
const dirNameArray = dirNameArg.split('/').filter(str => str.trim() !== ""); const dirNameArray = dirNameArg.split('/').filter(str => str.trim() !== "");
optionsArg = { optionsArg = {
@ -221,6 +234,17 @@ export class Directory {
return returnDirectory || null; return returnDirectory || null;
}; };
if (optionsArg.couldBeFilePath) {
const baseDirectory = await this.bucketRef.getBaseDirectory();
const existingFile = await baseDirectory.getFile({
path: dirNameArg,
});
if (existingFile) {
const adjustedPath = dirNameArg.substring(0, dirNameArg.lastIndexOf('/'));
return this.getSubDirectoryByName(adjustedPath);
}
}
let wantedDirectory: Directory | null = null; let wantedDirectory: Directory | null = null;
let counter = 0; let counter = 0;
for (const dirNameToSearch of dirNameArray) { for (const dirNameToSearch of dirNameArray) {
@ -336,7 +360,7 @@ export class Directory {
*/ */
mode?: 'permanent' | 'trash'; mode?: 'permanent' | 'trash';
}) { }) {
const file = await this.getFile({ const file = await this.getFileStrict({
path: optionsArg.path, path: optionsArg.path,
}); });
await file.delete({ await file.delete({

View File

@ -130,6 +130,29 @@ export class File {
await this.parentDirectoryRef.listFiles(); await this.parentDirectoryRef.listFiles();
} }
/**
* restores
*/
public async restore(optionsArg: {
useOriginalPath?: boolean;
toPath?: string;
overwrite?: boolean;
} = {}) {
optionsArg = {
useOriginalPath: (() => {
return optionsArg.toPath ? false : true;
})(),
overwrite: false,
...optionsArg,
};
const moveToPath = optionsArg.toPath || (await (await this.getMetaData()).getCustomMetaData({
key: 'recycle'
})).originalPath;
await this.move({
path: moveToPath,
})
}
/** /**
* allows locking the file * allows locking the file
* @param optionsArg * @param optionsArg
@ -154,7 +177,7 @@ export class File {
}) { }) {
const metadata = await this.getMetaData(); const metadata = await this.getMetaData();
await metadata.removeLock({ await metadata.removeLock({
force: optionsArg?.force, force: optionsArg?.force || false,
}); });
} }
@ -219,7 +242,10 @@ export class File {
// lets update references of this // lets update references of this
const baseDirectory = await this.parentDirectoryRef.bucketRef.getBaseDirectory(); const baseDirectory = await this.parentDirectoryRef.bucketRef.getBaseDirectory();
this.parentDirectoryRef = await baseDirectory.getSubDirectoryByNameStrict( this.parentDirectoryRef = await baseDirectory.getSubDirectoryByNameStrict(
pathDescriptorArg.directory?.getBasePath()! await helpers.reducePathDescriptorToPath(pathDescriptorArg),
{
couldBeFilePath: true,
}
); );
this.name = pathDescriptorArg.path!; this.name = pathDescriptorArg.path!;
} }