Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 189 additions & 47 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"author": "Internxt <[email protected]>",
"version": "1.3.5",
"version": "1.3.0",
"description": "Internxt CLI to manage your encrypted storage",
"scripts": {
"build": "tsc",
Expand Down
82 changes: 25 additions & 57 deletions src/commands/move.ts → src/commands/move-file.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,44 @@
import { Command, Flags } from '@oclif/core';
import { ConfigService } from '../services/config.service';
import { DriveFolderService } from '../services/drive/drive-folder.service';
import { CLIUtils } from '../utils/cli.utils';
import {
ItemNotFoundError,
MissingCredentialsError,
NotValidFolderUuidError,
NotValidItemUuidError,
} from '../types/command.types';
import { MissingCredentialsError, NotValidFileUuidError, NotValidFolderUuidError } from '../types/command.types';
import { ValidationService } from '../services/validation.service';
import { DriveFileService } from '../services/drive/drive-file.service';
import { DriveFileItem, DriveFolderItem } from '../types/drive.types';
import { ErrorUtils } from '../utils/errors.utils';

export default class Move extends Command {
export default class MoveFile extends Command {
static readonly args = {};
static readonly description = 'Move a folder/file into a destination folder.';

static readonly description = 'Move a file into a destination folder.';
static readonly aliases = ['move:file'];
static readonly examples = ['<%= config.bin %> <%= command.id %>'];

static readonly flags = {
...CLIUtils.CommonFlags,
id: Flags.string({
char: 'i',
description: 'The item id to be moved (it can be a file id or a folder id).',
description: 'The file id to be moved.',
required: false,
}),
destination: Flags.string({
char: 'd',
description: 'The destination folder id where the item is going to be moved.',
description: 'The destination folder id where the file is going to be moved.',
required: false,
}),
};

public async run() {
const { flags } = await this.parse(Move);
const { flags } = await this.parse(MoveFile);

const nonInteractive = flags['non-interactive'];

const userCredentials = await ConfigService.instance.readUser();
if (!userCredentials) throw new MissingCredentialsError();

const itemUuid = await this.getItemUuid(flags['id'], nonInteractive);
const fileUuid = await this.getFileUuid(flags['id'], nonInteractive);
const destinationFolderUuid = await this.getDestinationFolderUuid(flags['destination'], nonInteractive);

let item: DriveFileItem | DriveFolderItem | undefined;
let isFolder = false;
try {
if (!item) {
item = await DriveFileService.instance.getFileMetadata(itemUuid);
isFolder = false;
}
} catch {
/* noop */
}
try {
if (!item) {
item = await DriveFolderService.instance.getFolderMetaByUuid(itemUuid);
isFolder = true;
}
} catch {
/* noop */
}

if (!item) throw new ItemNotFoundError();

if (isFolder) {
await DriveFolderService.instance.moveFolder({ folderUuid: item.uuid, destinationFolderUuid });
} else {
await DriveFileService.instance.moveFile({ fileUuid: item.uuid, destinationFolderUuid });
}
CLIUtils.success(`${isFolder ? 'Folder' : 'File'} moved successfully to: ${destinationFolderUuid}`);
await DriveFileService.instance.moveFile({ fileUuid, destinationFolderUuid });
CLIUtils.success(`File moved successfully to: ${destinationFolderUuid}`);
}

async catch(error: Error) {
Expand All @@ -79,21 +47,21 @@ export default class Move extends Command {
this.exit(1);
}

public getItemUuid = async (itemUuidFlag: string | undefined, nonInteractive: boolean): Promise<string> => {
let itemUuid = CLIUtils.getValueFromFlag(
public getFileUuid = async (fileUuidFlag: string | undefined, nonInteractive: boolean): Promise<string> => {
let fileUuid = CLIUtils.getValueFromFlag(
{
value: itemUuidFlag,
name: Move.flags['id'].name,
error: new NotValidItemUuidError(),
value: fileUuidFlag,
name: MoveFile.flags['id'].name,
error: new NotValidFileUuidError(),
canBeEmpty: true,
},
nonInteractive,
(itemUuid: string) => ValidationService.instance.validateUUIDv4(itemUuid),
(fileUuid: string) => ValidationService.instance.validateUUIDv4(fileUuid),
);
if (!itemUuid) {
itemUuid = (await this.getItemUuidInteractively()).trim();
if (!fileUuid) {
fileUuid = (await this.getFileUuidInteractively()).trim();
}
return itemUuid;
return fileUuid;
};

public getDestinationFolderUuid = async (
Expand All @@ -103,7 +71,7 @@ export default class Move extends Command {
let destinationFolderUuid = CLIUtils.getValueFromFlag(
{
value: destinationFolderUuidFlag,
name: Move.flags['destination'].name,
name: MoveFile.flags['destination'].name,
error: new NotValidFolderUuidError(),
canBeEmpty: true,
},
Expand All @@ -118,14 +86,14 @@ export default class Move extends Command {

private static readonly MAX_ATTEMPTS = 3;

public getItemUuidInteractively = (): Promise<string> => {
public getFileUuidInteractively = (): Promise<string> => {
return CLIUtils.promptWithAttempts(
{
message: 'What is the item id you want to move?',
message: 'What is the file id you want to move?',
options: { required: true },
error: new NotValidItemUuidError(),
error: new NotValidFileUuidError(),
},
Move.MAX_ATTEMPTS,
MoveFile.MAX_ATTEMPTS,
ValidationService.instance.validateUUIDv4,
);
};
Expand All @@ -137,7 +105,7 @@ export default class Move extends Command {
options: { required: true },
error: new NotValidFolderUuidError(),
},
Move.MAX_ATTEMPTS,
MoveFile.MAX_ATTEMPTS,
ValidationService.instance.validateUUIDv4,
);
};
Expand Down
112 changes: 112 additions & 0 deletions src/commands/move-folder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Command, Flags } from '@oclif/core';
import { ConfigService } from '../services/config.service';
import { DriveFolderService } from '../services/drive/drive-folder.service';
import { CLIUtils } from '../utils/cli.utils';
import { MissingCredentialsError, NotValidFolderUuidError } from '../types/command.types';
import { ValidationService } from '../services/validation.service';
import { ErrorUtils } from '../utils/errors.utils';

export default class MoveFolder extends Command {
static readonly args = {};
static readonly description = 'Move a folder into a destination folder.';
static readonly aliases = ['move:folder'];
static readonly examples = ['<%= config.bin %> <%= command.id %>'];

static readonly flags = {
...CLIUtils.CommonFlags,
id: Flags.string({
char: 'i',
description: 'The folder id to be moved.',
required: false,
}),
destination: Flags.string({
char: 'd',
description: 'The destination folder id where the folder is going to be moved.',
required: false,
}),
};

public async run() {
const { flags } = await this.parse(MoveFolder);

const nonInteractive = flags['non-interactive'];

const userCredentials = await ConfigService.instance.readUser();
if (!userCredentials) throw new MissingCredentialsError();

const folderUuid = await this.getFolderUuid(flags['id'], nonInteractive);
const destinationFolderUuid = await this.getDestinationFolderUuid(flags['destination'], nonInteractive);

await DriveFolderService.instance.moveFolder({ folderUuid, destinationFolderUuid });
CLIUtils.success(`Folder moved successfully to: ${destinationFolderUuid}`);
}

async catch(error: Error) {
ErrorUtils.report(error, { command: this.id });
CLIUtils.error(error.message);
this.exit(1);
}

public getFolderUuid = async (folderUuidFlag: string | undefined, nonInteractive: boolean): Promise<string> => {
let folderUuid = CLIUtils.getValueFromFlag(
{
value: folderUuidFlag,
name: MoveFolder.flags['id'].name,
error: new NotValidFolderUuidError(),
canBeEmpty: true,
},
nonInteractive,
(folderUuid: string) => ValidationService.instance.validateUUIDv4(folderUuid),
);
if (!folderUuid) {
folderUuid = (await this.getFolderUuidInteractively()).trim();
}
return folderUuid;
};

public getDestinationFolderUuid = async (
destinationFolderUuidFlag: string | undefined,
nonInteractive: boolean,
): Promise<string> => {
let destinationFolderUuid = CLIUtils.getValueFromFlag(
{
value: destinationFolderUuidFlag,
name: MoveFolder.flags['destination'].name,
error: new NotValidFolderUuidError(),
canBeEmpty: true,
},
nonInteractive,
(folderUuid: string) => ValidationService.instance.validateUUIDv4(folderUuid),
);
if (!destinationFolderUuid) {
destinationFolderUuid = (await this.getDestinationFolderUuidInteractively()).trim();
}
return destinationFolderUuid;
};

private static readonly MAX_ATTEMPTS = 3;

public getFolderUuidInteractively = (): Promise<string> => {
return CLIUtils.promptWithAttempts(
{
message: 'What is the folder id you want to move?',
options: { required: true },
error: new NotValidFolderUuidError(),
},
MoveFolder.MAX_ATTEMPTS,
ValidationService.instance.validateUUIDv4,
);
};

public getDestinationFolderUuidInteractively = (): Promise<string> => {
return CLIUtils.promptWithAttempts(
{
message: 'What is the destination folder id?',
options: { required: true },
error: new NotValidFolderUuidError(),
},
MoveFolder.MAX_ATTEMPTS,
ValidationService.instance.validateUUIDv4,
);
};
}
4 changes: 2 additions & 2 deletions src/commands/rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ export default class Rename extends Command {
...CLIUtils.CommonFlags,
id: Flags.string({
char: 'i',
description: 'The item id to be renamed (it can be a file id or a folder id).',
description: 'The ID of the item to rename (can be a file ID or a folder ID).',
required: false,
}),
name: Flags.string({
char: 'n',
description: 'The new item name that the item is going to be have.',
description: 'The new name for the item.',
required: false,
}),
};
Expand Down
Loading