1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 11:24:35 +00:00

chore: drive all endpoints docs generated

This commit is contained in:
Saad Jutt
2021-11-10 21:59:46 +05:00
parent 31959455c3
commit 45fbf2df46
5 changed files with 349 additions and 63 deletions

View File

@@ -84,6 +84,73 @@ components:
- fileTree
type: object
additionalProperties: false
GetFileResponse:
properties:
status:
type: string
fileContent:
type: string
message:
type: string
required:
- status
type: object
additionalProperties: false
UpdateFileResponse:
properties:
status:
type: string
message:
type: string
required:
- status
type: object
additionalProperties: false
FilePayload:
properties:
filePath:
type: string
description: 'Path of the file'
example: /Public/somefolder/some.file
fileContent:
type: string
description: 'Contents of the file'
example: 'Contents of the File'
required:
- filePath
- fileContent
type: object
additionalProperties: false
TreeNode:
properties:
name:
type: string
relativePath:
type: string
absolutePath:
type: string
children:
items:
$ref: '#/components/schemas/TreeNode'
type: array
required:
- name
- relativePath
- absolutePath
- children
type: object
additionalProperties: false
GetFileTreeResponse:
properties:
status:
type: string
tree:
$ref: '#/components/schemas/TreeNode'
required:
- status
- tree
type: object
additionalProperties: false
UserResponse:
properties:
id:
@@ -348,6 +415,92 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/DeployPayload'
/SASjsApi/drive/file:
get:
operationId: GetFile
responses:
'200':
description: Ok
content:
application/json:
schema:
$ref: '#/components/schemas/GetFileResponse'
examples:
'Example 1':
value: {status: success, fileContent: 'Contents of the File'}
'400':
description: 'Unable to get File'
content:
application/json:
schema:
$ref: '#/components/schemas/GetFileResponse'
examples:
'Example 1':
value: {status: failure, message: 'File request failed.'}
description: 'Get file from SASjs Drive'
tags:
- Drive
security:
-
bearerAuth: []
parameters:
-
in: query
name: filePath
required: true
schema:
type: string
patch:
operationId: UpdateFile
responses:
'200':
description: Ok
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateFileResponse'
examples:
'Example 1':
value: {status: success}
'400':
description: 'Unable to get File'
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateFileResponse'
examples:
'Example 1':
value: {status: failure, message: 'File request failed.'}
description: 'Modify a file in SASjs Drive'
tags:
- Drive
security:
-
bearerAuth: []
parameters: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FilePayload'
/SASjsApi/drive/filetree:
get:
operationId: GetFileTree
responses:
'200':
description: Ok
content:
application/json:
schema:
$ref: '#/components/schemas/GetFileTreeResponse'
description: 'Fetch file tree within SASjs Drive.'
tags:
- Drive
security:
-
bearerAuth: []
parameters: []
/SASjsApi/user:
get:
operationId: GetAllUsers

View File

@@ -1,13 +1,38 @@
import { Security, Route, Tags, Example, Post, Body, Response } from 'tsoa'
import {
Security,
Route,
Tags,
Example,
Post,
Body,
Response,
Query,
Get,
Patch
} from 'tsoa'
import { fileExists, readFile, createFile } from '@sasjs/utils'
import { createFileTree, getTreeExample } from '.'
import { createFileTree, ExecutionController, getTreeExample } from '.'
import { FileTree, isFileTree } from '../types'
import { FileTree, isFileQuery, isFileTree, TreeNode } from '../types'
import path from 'path'
import { getTmpFilesFolderPath } from '../utils'
interface DeployPayload {
appLoc?: string
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 {
status: string
@@ -15,18 +40,34 @@ interface DeployResponse {
example?: FileTree
}
interface GetFileResponse {
status: string
fileContent?: string
message?: string
}
interface GetFileTreeResponse {
status: string
tree: TreeNode
}
interface UpdateFileResponse {
status: string
message?: string
}
const fileTreeExample = getTreeExample()
const successResponse: DeployResponse = {
const successDeployResponse: DeployResponse = {
status: 'success',
message: 'Files deployed successfully to @sasjs/server.'
}
const invalidFormatResponse: DeployResponse = {
const invalidDeployFormatResponse: DeployResponse = {
status: 'failure',
message: 'Provided not supported data format.',
example: fileTreeExample
}
const execErrorResponse: DeployResponse = {
const execDeployErrorResponse: DeployResponse = {
status: 'failure',
message: 'Deployment failed!'
}
@@ -39,42 +80,122 @@ export class DriveController {
* Creates/updates files within SASjs Drive using provided payload.
*
*/
@Example<DeployResponse>(successResponse)
@Response<DeployResponse>(400, 'Invalid Format', invalidFormatResponse)
@Response<DeployResponse>(500, 'Execution Error', execErrorResponse)
@Example<DeployResponse>(successDeployResponse)
@Response<DeployResponse>(400, 'Invalid Format', invalidDeployFormatResponse)
@Response<DeployResponse>(500, 'Execution Error', execDeployErrorResponse)
@Post('/deploy')
public async deploy(@Body() body: DeployPayload): Promise<DeployResponse> {
return deploy(body)
}
async readFile(filePath: string) {
await this.validateFilePath(filePath)
return await readFile(filePath)
/**
* Get file from SASjs Drive
*
*/
@Example<GetFileResponse>({
status: 'success',
fileContent: 'Contents of the File'
})
@Response<GetFileResponse>(400, 'Unable to get File', {
status: 'failure',
message: 'File request failed.'
})
@Get('/file')
public async getFile(@Query() filePath: string): Promise<GetFileResponse> {
return getFile(filePath)
}
async updateFile(filePath: string, fileContent: string) {
await this.validateFilePath(filePath)
return await createFile(filePath, fileContent)
/**
* Modify a file in SASjs Drive
*
*/
@Example<UpdateFileResponse>({
status: 'success'
})
@Response<UpdateFileResponse>(400, 'Unable to get File', {
status: 'failure',
message: 'File request failed.'
})
@Patch('/file')
public async updateFile(
@Body() body: FilePayload
): Promise<UpdateFileResponse> {
return updateFile(body)
}
private async validateFilePath(filePath: string) {
if (!(await fileExists(filePath))) {
throw 'DriveController: File does not exists.'
}
/**
* Fetch file tree within SASjs Drive.
*
*/
@Get('/filetree')
public async getFileTree(): Promise<GetFileTreeResponse> {
return getFileTree()
}
}
const getFileTree = () => {
const tree = new ExecutionController().buildDirectorytree()
return { status: 'success', tree }
}
const deploy = async (data: DeployPayload) => {
if (!isFileTree(data.fileTree)) {
throw { code: 400, ...invalidFormatResponse }
throw { code: 400, ...invalidDeployFormatResponse }
}
await createFileTree(
data.fileTree.members,
data.appLoc ? data.appLoc.replace(/^\//, '').split('/') : []
).catch((err) => {
throw { code: 500, ...execErrorResponse, ...err }
throw { code: 500, ...execDeployErrorResponse, ...err }
})
return successResponse
return successDeployResponse
}
const getFile = async (filePath: string): Promise<GetFileResponse> => {
try {
const filePathFull = path
.join(getTmpFilesFolderPath(), filePath)
.replace(new RegExp('/', 'g'), path.sep)
await validateFilePath(filePathFull)
const fileContent = await readFile(filePathFull)
return { status: 'success', fileContent: fileContent }
} catch (err) {
throw {
code: 400,
status: 'failure',
message: 'File request failed.',
...(typeof err === 'object' ? err : { details: err })
}
}
}
const updateFile = async (body: FilePayload): Promise<GetFileResponse> => {
const { filePath, fileContent } = body
try {
const filePathFull = path
.join(getTmpFilesFolderPath(), filePath)
.replace(new RegExp('/', 'g'), path.sep)
await validateFilePath(filePathFull)
await createFile(filePathFull, fileContent)
return { status: 'success' }
} catch (err) {
throw {
code: 400,
status: 'failure',
message: 'File request failed.',
...(typeof err === 'object' ? err : { details: err })
}
}
}
const validateFilePath = async (filePath: string) => {
if (!(await fileExists(filePath))) {
throw 'DriveController: File does not exists.'
}
}

View File

@@ -3,7 +3,11 @@ import path from 'path'
import { ExecutionController } from '../../controllers'
import { DriveController } from '../../controllers/drive'
import { isFileQuery } from '../../types'
import { getTmpFilesFolderPath } from '../../utils'
import {
getFileDriveValidation,
getTmpFilesFolderPath,
updateFileDriveValidation
} from '../../utils'
const driveRouter = express.Router()
@@ -22,51 +26,47 @@ driveRouter.post('/deploy', async (req, res) => {
})
driveRouter.get('/file', async (req, res) => {
if (isFileQuery(req.query)) {
const filePath = path
.join(getTmpFilesFolderPath(), req.query.filePath)
.replace(new RegExp('/', 'g'), path.sep)
await new DriveController()
.readFile(filePath)
.then((fileContent) => {
res.status(200).send({ status: 'success', fileContent: fileContent })
})
.catch((err) => {
res.status(400).send({
status: 'failure',
message: 'File request failed.',
...(typeof err === 'object' ? err : { details: err })
})
})
} else {
res.status(400).send({
status: 'failure',
message: 'Invalid Request: Expected parameter filePath was not provided'
})
const { error, value: query } = getFileDriveValidation(req.query)
if (error) return res.status(400).send(error.details[0].message)
const controller = new DriveController()
try {
const response = await controller.getFile(query.filePath)
res.send(response)
} catch (err: any) {
const statusCode = err.code
delete err.code
res.status(statusCode).send(err)
}
})
driveRouter.patch('/file', async (req, res) => {
const filePath = path
.join(getTmpFilesFolderPath(), req.body.filePath)
.replace(new RegExp('/', 'g'), path.sep)
await new DriveController()
.updateFile(filePath, req.body.fileContent)
.then(() => {
res.status(200).send({ status: 'success' })
})
.catch((err) => {
res.status(400).send({
status: 'failure',
message: 'File request failed.',
...(typeof err === 'object' ? err : { details: err })
})
})
const { error, value: body } = updateFileDriveValidation(req.body)
if (error) return res.status(400).send(error.details[0].message)
const controller = new DriveController()
try {
const response = await controller.updateFile(body)
res.send(response)
} catch (err: any) {
const statusCode = err.code
delete err.code
res.status(statusCode).send(err)
}
})
driveRouter.get('/fileTree', async (req, res) => {
const tree = new ExecutionController().buildDirectorytree()
res.status(200).send({ status: 'success', tree })
const controller = new DriveController()
try {
const response = await controller.getFileTree()
res.send(response)
} catch (err: any) {
res.status(403).send(err.toString())
}
})
export default driveRouter

View File

@@ -65,3 +65,14 @@ export const registerClientValidation = (data: any): Joi.ValidationResult =>
clientId: Joi.string().required(),
clientSecret: Joi.string().required()
}).validate(data)
export const getFileDriveValidation = (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)

View File

@@ -3,8 +3,9 @@
"version": "0.0.1",
"description": "NodeJS wrapper for calling the SAS binary executable",
"scripts": {
"server:install": "cd web && npm ci && cd ../api && npm ci",
"server": "cd web && npm run build && cd ../api && npm run start:prod",
"server": "npm run server:prepare && npm run server:start",
"server:prepare": "cd web && npm ci && npm run build && cd ../api && npm ci && cd ..",
"server:start": "cd api && npm run start:prod",
"lint-api:fix": "npx prettier --write \"api/src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
"lint-api": "npx prettier --check \"api/src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
"lint-web:fix": "npx prettier --write \"web/src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",