1
0
mirror of https://github.com/sasjs/server.git synced 2026-01-14 17:30:05 +00:00

feat(drive): new route delete file api

This commit is contained in:
Saad Jutt
2022-03-14 05:30:10 +05:00
parent 7072e282b1
commit 3d583ff21d
4 changed files with 130 additions and 46 deletions

View File

@@ -585,6 +585,7 @@ paths:
responses: responses:
'204': '204':
description: 'No content' description: 'No content'
description: "It's optional to either provide `_filePath` in url as query parameter\nOr provide `filePath` in body as form field.\nBut it's required to provide else API will respond with Bad Request."
summary: 'Get file from SASjs Drive' summary: 'Get file from SASjs Drive'
tags: tags:
- Drive - Drive
@@ -594,11 +595,57 @@ paths:
parameters: parameters:
- -
in: query in: query
name: filePath name: _filePath
required: true required: false
schema: schema:
type: string type: string
example: /Public/somefolder/some.file example: /Public/somefolder/some.file
requestBody:
required: false
content:
multipart/form-data:
schema:
type: object
properties:
filePath:
type: string
delete:
operationId: DeleteFile
responses:
'200':
description: Ok
content:
application/json:
schema:
properties:
status: {type: string}
required:
- status
type: object
description: "It's optional to either provide `_filePath` in url as query parameter\nOr provide `filePath` in body as form field.\nBut it's required to provide else API will respond with Bad Request."
summary: 'Delete file from SASjs Drive'
tags:
- Drive
security:
-
bearerAuth: []
parameters:
-
in: query
name: _filePath
required: false
schema:
type: string
example: /Public/somefolder/some.file
requestBody:
required: false
content:
multipart/form-data:
schema:
type: object
properties:
filePath:
type: string
post: post:
operationId: SaveFile operationId: SaveFile
responses: responses:

View File

@@ -13,9 +13,15 @@ import {
Get, Get,
Patch, Patch,
UploadedFile, UploadedFile,
FormField FormField,
Delete
} from 'tsoa' } from 'tsoa'
import { fileExists, createFile, moveFile, createFolder } from '@sasjs/utils' import {
fileExists,
moveFile,
createFolder,
deleteFile as deleteFileOnSystem
} from '@sasjs/utils'
import { createFileTree, ExecutionController, getTreeExample } from './internal' import { createFileTree, ExecutionController, getTreeExample } from './internal'
import { FileTree, isFileTree, TreeNode } from '../types' import { FileTree, isFileTree, TreeNode } from '../types'
@@ -25,18 +31,6 @@ interface DeployPayload {
appLoc?: string appLoc?: string
fileTree: FileTree fileTree: FileTree
} }
interface FilePayload {
/**
* Path of the file
* @example "/Public/somefolder/some.file"
*/
filePath: string
/**
* Contents of the file
* @example "Contents of the File"
*/
fileContent: string
}
interface DeployResponse { interface DeployResponse {
status: string status: string
@@ -93,16 +87,39 @@ export class DriveController {
} }
/** /**
* It's optional to either provide `_filePath` in url as query parameter
* Or provide `filePath` in body as form field.
* But it's required to provide else API will respond with Bad Request.
*
* @summary Get file from SASjs Drive * @summary Get file from SASjs Drive
* @query filePath Location of SAS program * @query _filePath Location of SAS program
* @example filePath "/Public/somefolder/some.file" * @example _filePath "/Public/somefolder/some.file"
*/ */
@Get('/file') @Get('/file')
public async getFile( public async getFile(
@Request() request: express.Request, @Request() request: express.Request,
@Query() filePath: string
@Query() _filePath?: string,
@FormField() filePath?: string
) { ) {
return getFile(request, filePath) return getFile(request, (_filePath ?? filePath)!)
}
/**
* It's optional to either provide `_filePath` in url as query parameter
* Or provide `filePath` in body as form field.
* But it's required to provide else API will respond with Bad Request.
*
* @summary Delete file from SASjs Drive
* @query _filePath Location of SAS program
* @example _filePath "/Public/somefolder/some.file"
*/
@Delete('/file')
public async deleteFile(
@Query() _filePath?: string,
@FormField() filePath?: string
) {
return deleteFile((_filePath ?? filePath)!)
} }
/** /**
@@ -210,6 +227,26 @@ const getFile = async (req: express.Request, filePath: string) => {
req.res?.sendFile(path.resolve(filePathFull)) req.res?.sendFile(path.resolve(filePathFull))
} }
const deleteFile = async (filePath: string) => {
const driveFilesPath = getTmpFilesFolderPath()
const filePathFull = path
.join(getTmpFilesFolderPath(), filePath)
.replace(new RegExp('/', 'g'), path.sep)
if (!filePathFull.includes(driveFilesPath)) {
throw new Error('Cannot delete file outside drive.')
}
if (!(await fileExists(filePathFull))) {
throw new Error('File does not exist.')
}
await deleteFileOnSystem(filePathFull)
return { status: 'success' }
}
const saveFile = async ( const saveFile = async (
filePath: string, filePath: string,
multerFile: Express.Multer.File multerFile: Express.Multer.File

View File

@@ -3,12 +3,7 @@ import { deleteFile } from '@sasjs/utils'
import { multerSingle } from '../../middlewares/multer' import { multerSingle } from '../../middlewares/multer'
import { DriveController } from '../../controllers/' import { DriveController } from '../../controllers/'
import { import { fileBodyValidation, fileParamValidation } from '../../utils'
getFileDriveValidation,
updateFileDriveValidation,
uploadFileBodyValidation,
uploadFileParamValidation
} from '../../utils'
const controller = new DriveController() const controller = new DriveController()
@@ -28,11 +23,27 @@ driveRouter.post('/deploy', async (req, res) => {
}) })
driveRouter.get('/file', async (req, res) => { driveRouter.get('/file', async (req, res) => {
const { error, value: query } = getFileDriveValidation(req.query) const { error: errQ, value: query } = fileParamValidation(req.query)
if (error) return res.status(400).send(error.details[0].message) const { error: errB, value: body } = fileBodyValidation(req.body)
if (errQ && errB) return res.status(400).send(errB.details[0].message)
try { try {
await controller.getFile(req, query.filePath) await controller.getFile(req, query._filePath, body.filePath)
} catch (err: any) {
res.status(403).send(err.toString())
}
})
driveRouter.delete('/file', async (req, res) => {
const { error: errQ, value: query } = fileParamValidation(req.query)
const { error: errB, value: body } = fileBodyValidation(req.body)
if (errQ && errB) return res.status(400).send(errB.details[0].message)
try {
const response = await controller.deleteFile(query._filePath, body.filePath)
res.send(response)
} catch (err: any) { } catch (err: any) {
res.status(403).send(err.toString()) res.status(403).send(err.toString())
} }
@@ -42,8 +53,8 @@ driveRouter.post(
'/file', '/file',
(...arg) => multerSingle('file', arg), (...arg) => multerSingle('file', arg),
async (req, res) => { async (req, res) => {
const { error: errQ, value: query } = uploadFileParamValidation(req.query) const { error: errQ, value: query } = fileParamValidation(req.query)
const { error: errB, value: body } = uploadFileBodyValidation(req.body) const { error: errB, value: body } = fileBodyValidation(req.body)
if (errQ && errB) { if (errQ && errB) {
if (req.file) await deleteFile(req.file.path) if (req.file) await deleteFile(req.file.path)
@@ -70,8 +81,8 @@ driveRouter.patch(
'/file', '/file',
(...arg) => multerSingle('file', arg), (...arg) => multerSingle('file', arg),
async (req, res) => { async (req, res) => {
const { error: errQ, value: query } = uploadFileParamValidation(req.query) const { error: errQ, value: query } = fileParamValidation(req.query)
const { error: errB, value: body } = uploadFileBodyValidation(req.body) const { error: errB, value: body } = fileBodyValidation(req.body)
if (errQ && errB) { if (errQ && errB) {
if (req.file) await deleteFile(req.file.path) if (req.file) await deleteFile(req.file.path)

View File

@@ -66,25 +66,14 @@ export const registerClientValidation = (data: any): Joi.ValidationResult =>
clientSecret: Joi.string().required() clientSecret: Joi.string().required()
}).validate(data) }).validate(data)
export const getFileDriveValidation = (data: any): Joi.ValidationResult => export const fileBodyValidation = (data: any): Joi.ValidationResult =>
Joi.object({
filePath: Joi.string().required()
}).validate(data)
export const updateFileDriveValidation = (data: any): Joi.ValidationResult =>
Joi.object({
filePath: Joi.string().required(),
fileContent: Joi.string().required()
}).validate(data)
export const uploadFileBodyValidation = (data: any): Joi.ValidationResult =>
Joi.object({ Joi.object({
filePath: Joi.string().pattern(/.sas$/).required().messages({ filePath: Joi.string().pattern(/.sas$/).required().messages({
'string.pattern.base': `Valid extensions for filePath: .sas` 'string.pattern.base': `Valid extensions for filePath: .sas`
}) })
}).validate(data) }).validate(data)
export const uploadFileParamValidation = (data: any): Joi.ValidationResult => export const fileParamValidation = (data: any): Joi.ValidationResult =>
Joi.object({ Joi.object({
_filePath: Joi.string().pattern(/.sas$/).required().messages({ _filePath: Joi.string().pattern(/.sas$/).required().messages({
'string.pattern.base': `Valid extensions for filePath: .sas` 'string.pattern.base': `Valid extensions for filePath: .sas`