mirror of
https://github.com/sasjs/server.git
synced 2026-01-11 00:10:06 +00:00
chore: drive auto-generated swagger
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,5 @@ node_modules/
|
|||||||
sas/
|
sas/
|
||||||
tmp/
|
tmp/
|
||||||
build/
|
build/
|
||||||
public/
|
|
||||||
certificates/
|
certificates/
|
||||||
.env
|
.env
|
||||||
|
|||||||
553
public/swagger.yaml
Normal file
553
public/swagger.yaml
Normal file
@@ -0,0 +1,553 @@
|
|||||||
|
components:
|
||||||
|
examples: {}
|
||||||
|
headers: {}
|
||||||
|
parameters: {}
|
||||||
|
requestBodies: {}
|
||||||
|
responses: {}
|
||||||
|
schemas:
|
||||||
|
MemberType.folder:
|
||||||
|
enum:
|
||||||
|
- folder
|
||||||
|
type: string
|
||||||
|
FolderMember:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/MemberType.folder'
|
||||||
|
members:
|
||||||
|
items:
|
||||||
|
anyOf:
|
||||||
|
-
|
||||||
|
$ref: '#/components/schemas/FolderMember'
|
||||||
|
-
|
||||||
|
$ref: '#/components/schemas/ServiceMember'
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- type
|
||||||
|
- members
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
MemberType.service:
|
||||||
|
enum:
|
||||||
|
- service
|
||||||
|
type: string
|
||||||
|
ServiceMember:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/MemberType.service'
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- type
|
||||||
|
- code
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
FileTree:
|
||||||
|
properties:
|
||||||
|
members:
|
||||||
|
items:
|
||||||
|
anyOf:
|
||||||
|
-
|
||||||
|
$ref: '#/components/schemas/FolderMember'
|
||||||
|
-
|
||||||
|
$ref: '#/components/schemas/ServiceMember'
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- members
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
DeployResponse:
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
$ref: '#/components/schemas/FileTree'
|
||||||
|
required:
|
||||||
|
- status
|
||||||
|
- message
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
DeployPayload:
|
||||||
|
properties:
|
||||||
|
appLoc:
|
||||||
|
type: string
|
||||||
|
fileTree:
|
||||||
|
$ref: '#/components/schemas/FileTree'
|
||||||
|
required:
|
||||||
|
- fileTree
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
UserResponse:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- username
|
||||||
|
- displayName
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
UserDetailsResponse:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
isActive:
|
||||||
|
type: boolean
|
||||||
|
isAdmin:
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- displayName
|
||||||
|
- username
|
||||||
|
- isActive
|
||||||
|
- isAdmin
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
UserPayload:
|
||||||
|
properties:
|
||||||
|
displayName:
|
||||||
|
type: string
|
||||||
|
description: 'Display name for user'
|
||||||
|
example: 'John Snow'
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: 'Username for user'
|
||||||
|
example: johnSnow01
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
description: 'Password for user'
|
||||||
|
isAdmin:
|
||||||
|
type: boolean
|
||||||
|
description: 'Account should be admin or not, defaults to false'
|
||||||
|
example: 'false'
|
||||||
|
isActive:
|
||||||
|
type: boolean
|
||||||
|
description: 'Account should be active or not, defaults to true'
|
||||||
|
example: 'true'
|
||||||
|
required:
|
||||||
|
- displayName
|
||||||
|
- username
|
||||||
|
- password
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
ClientPayload:
|
||||||
|
properties:
|
||||||
|
clientId:
|
||||||
|
type: string
|
||||||
|
description: 'Client ID'
|
||||||
|
example: someFormattedClientID1234
|
||||||
|
clientSecret:
|
||||||
|
type: string
|
||||||
|
description: 'Client Secret'
|
||||||
|
example: someRandomCryptoString
|
||||||
|
required:
|
||||||
|
- clientId
|
||||||
|
- clientSecret
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
AuthorizeResponse:
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
description: 'Authorization code'
|
||||||
|
example: someRandomCryptoString
|
||||||
|
required:
|
||||||
|
- code
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
AuthorizePayload:
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: 'Username for user'
|
||||||
|
example: johnSnow01
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
description: 'Password for user'
|
||||||
|
example: secretpassword
|
||||||
|
clientId:
|
||||||
|
type: string
|
||||||
|
description: 'Client ID'
|
||||||
|
example: someFormattedClientID1234
|
||||||
|
required:
|
||||||
|
- username
|
||||||
|
- password
|
||||||
|
- clientId
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
TokenResponse:
|
||||||
|
properties:
|
||||||
|
accessToken:
|
||||||
|
type: string
|
||||||
|
description: 'Access Token'
|
||||||
|
example: someRandomCryptoString
|
||||||
|
refreshToken:
|
||||||
|
type: string
|
||||||
|
description: 'Refresh Token'
|
||||||
|
example: someRandomCryptoString
|
||||||
|
required:
|
||||||
|
- accessToken
|
||||||
|
- refreshToken
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
TokenPayload:
|
||||||
|
properties:
|
||||||
|
clientId:
|
||||||
|
type: string
|
||||||
|
description: 'Client ID'
|
||||||
|
example: someFormattedClientID1234
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
description: 'Authorization code'
|
||||||
|
example: someRandomCryptoString
|
||||||
|
required:
|
||||||
|
- clientId
|
||||||
|
- code
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
InfoJWT:
|
||||||
|
properties:
|
||||||
|
clientId:
|
||||||
|
type: string
|
||||||
|
userId:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
required:
|
||||||
|
- clientId
|
||||||
|
- userId
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
securitySchemes:
|
||||||
|
bearerAuth:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
info:
|
||||||
|
title: server
|
||||||
|
version: 0.0.1
|
||||||
|
description: 'SASjs server'
|
||||||
|
contact:
|
||||||
|
name: 'Analytium Ltd'
|
||||||
|
openapi: 3.0.0
|
||||||
|
paths:
|
||||||
|
/SASjsApi/drive/deploy:
|
||||||
|
post:
|
||||||
|
operationId: Deploy
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DeployResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {status: success, message: 'Files deployed successfully to @sasjs/server.'}
|
||||||
|
'400':
|
||||||
|
description: 'Invalid Format'
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DeployResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {status: failure, message: 'Provided not supported data format.'}
|
||||||
|
'500':
|
||||||
|
description: 'Execution Error'
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DeployResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {status: failure, message: 'Deployment failed!'}
|
||||||
|
description: 'Creates/updates files within SASjs Drive using provided payload.'
|
||||||
|
tags:
|
||||||
|
- Drive
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/DeployPayload'
|
||||||
|
/SASjsApi/user:
|
||||||
|
get:
|
||||||
|
operationId: GetAllUsers
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UserResponse'
|
||||||
|
type: array
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: [{id: 123, username: johnusername, displayName: John}, {id: 456, username: starkusername, displayName: Stark}]
|
||||||
|
description: 'Get list of all users (username, displayname). All users can request this.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
post:
|
||||||
|
operationId: CreateUser
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
|
||||||
|
description: 'Create user with the following attributes: UserId, UserName, Password, isAdmin, isActive. Admin only task.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserPayload'
|
||||||
|
'/SASjsApi/user/{userId}':
|
||||||
|
get:
|
||||||
|
operationId: GetUser
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
|
description: 'Get user properties - such as group memberships, userName, displayName.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The user''s identifier'
|
||||||
|
in: path
|
||||||
|
name: userId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: 1234
|
||||||
|
patch:
|
||||||
|
operationId: UpdateUser
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
|
||||||
|
description: 'Update user properties - such as displayName. Can be performed either by admins, or the user in question.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The user''s identifier'
|
||||||
|
in: path
|
||||||
|
name: userId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: '1234'
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserPayload'
|
||||||
|
delete:
|
||||||
|
operationId: DeleteUser
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: 'No content'
|
||||||
|
description: 'Delete a user. Can be performed either by admins, or the user in question.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The user''s identifier'
|
||||||
|
in: path
|
||||||
|
name: userId
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
format: double
|
||||||
|
type: number
|
||||||
|
example: 1234
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
/SASjsApi/client:
|
||||||
|
post:
|
||||||
|
operationId: CreateClient
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ClientPayload'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString}
|
||||||
|
description: 'Create client with the following attributes: ClientId, ClientSecret. Admin only task.'
|
||||||
|
tags:
|
||||||
|
- Client
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/ClientPayload'
|
||||||
|
/SASjsApi/auth/authorize:
|
||||||
|
post:
|
||||||
|
operationId: Authorize
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthorizeResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {code: someRandomCryptoString}
|
||||||
|
description: 'Accept a valid username/password, plus a CLIENT_ID, and return an AUTH_CODE'
|
||||||
|
tags:
|
||||||
|
- Auth
|
||||||
|
security: []
|
||||||
|
parameters: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthorizePayload'
|
||||||
|
/SASjsApi/auth/token:
|
||||||
|
post:
|
||||||
|
operationId: Token
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TokenResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {accessToken: someRandomCryptoString, refreshToken: someRandomCryptoString}
|
||||||
|
description: 'Accepts client/auth code and returns access/refresh tokens'
|
||||||
|
tags:
|
||||||
|
- Auth
|
||||||
|
security: []
|
||||||
|
parameters: []
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TokenPayload'
|
||||||
|
/SASjsApi/auth/refresh:
|
||||||
|
post:
|
||||||
|
operationId: Refresh
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/TokenResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {accessToken: someRandomCryptoString, refreshToken: someRandomCryptoString}
|
||||||
|
description: 'Returns new access/refresh tokens'
|
||||||
|
tags:
|
||||||
|
- Auth
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
/SASjsApi/auth/logout:
|
||||||
|
post:
|
||||||
|
operationId: Logout
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: 'No content'
|
||||||
|
description: 'Logout terminate access/refresh tokens and returns nothing'
|
||||||
|
tags:
|
||||||
|
- Auth
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters: []
|
||||||
|
servers:
|
||||||
|
-
|
||||||
|
url: /
|
||||||
|
tags:
|
||||||
|
-
|
||||||
|
name: User
|
||||||
|
description: 'Operations about users'
|
||||||
|
-
|
||||||
|
name: Client
|
||||||
|
description: 'Operations about clients'
|
||||||
|
-
|
||||||
|
name: Auth
|
||||||
|
description: 'Operations about auth'
|
||||||
|
-
|
||||||
|
name: Drive
|
||||||
|
description: 'Operations about drive'
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { MemberType, FolderMember, ServiceMember } from '../types'
|
import { MemberType, FolderMember, ServiceMember, FileTree } from '../types'
|
||||||
import { getTmpFilesFolderPath } from '../utils/file'
|
import { getTmpFilesFolderPath } from '../utils/file'
|
||||||
import { createFolder, createFile, asyncForEach } from '@sasjs/utils'
|
import { createFolder, createFile, asyncForEach } from '@sasjs/utils'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
|
||||||
// REFACTOR: export FileTreeCpntroller
|
// REFACTOR: export FileTreeCpntroller
|
||||||
export const createFileTree = async (
|
export const createFileTree = async (
|
||||||
members: [FolderMember, ServiceMember],
|
members: (FolderMember | ServiceMember)[],
|
||||||
parentFolders: string[] = []
|
parentFolders: string[] = []
|
||||||
) => {
|
) => {
|
||||||
const destinationPath = path.join(
|
const destinationPath = path.join(
|
||||||
@@ -16,7 +16,7 @@ export const createFileTree = async (
|
|||||||
await asyncForEach(members, async (member: FolderMember | ServiceMember) => {
|
await asyncForEach(members, async (member: FolderMember | ServiceMember) => {
|
||||||
let name = member.name
|
let name = member.name
|
||||||
|
|
||||||
if (member.type === 'service') name += '.sas'
|
if (member.type === MemberType.service) name += '.sas'
|
||||||
|
|
||||||
if (member.type === MemberType.folder) {
|
if (member.type === MemberType.folder) {
|
||||||
await createFolder(path.join(destinationPath, name)).catch((err) =>
|
await createFolder(path.join(destinationPath, name)).catch((err) =>
|
||||||
@@ -36,19 +36,19 @@ export const createFileTree = async (
|
|||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTreeExample = () => ({
|
export const getTreeExample = (): FileTree => ({
|
||||||
members: [
|
members: [
|
||||||
{
|
{
|
||||||
name: 'jobs',
|
name: 'jobs',
|
||||||
type: 'folder',
|
type: MemberType.folder,
|
||||||
members: [
|
members: [
|
||||||
{
|
{
|
||||||
name: 'extract',
|
name: 'extract',
|
||||||
type: 'folder',
|
type: MemberType.folder,
|
||||||
members: [
|
members: [
|
||||||
{
|
{
|
||||||
name: 'makedata1',
|
name: 'makedata1',
|
||||||
type: 'service',
|
type: MemberType.service,
|
||||||
code: '%put Hello World!;'
|
code: '%put Hello World!;'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
63
src/controllers/drive.ts
Normal file
63
src/controllers/drive.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { Security, Route, Tags, Example, Post, Body, Response } from 'tsoa'
|
||||||
|
import { createFileTree, getTreeExample } from '.'
|
||||||
|
|
||||||
|
import { FileTree, isFileTree } from '../types'
|
||||||
|
|
||||||
|
interface DeployPayload {
|
||||||
|
appLoc?: string
|
||||||
|
fileTree: FileTree
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeployResponse {
|
||||||
|
status: string
|
||||||
|
message: string
|
||||||
|
example?: FileTree
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileTreeExample = getTreeExample()
|
||||||
|
|
||||||
|
const successResponse: DeployResponse = {
|
||||||
|
status: 'success',
|
||||||
|
message: 'Files deployed successfully to @sasjs/server.'
|
||||||
|
}
|
||||||
|
const invalidFormatResponse: DeployResponse = {
|
||||||
|
status: 'failure',
|
||||||
|
message: 'Provided not supported data format.',
|
||||||
|
example: fileTreeExample
|
||||||
|
}
|
||||||
|
const execErrorResponse: DeployResponse = {
|
||||||
|
status: 'failure',
|
||||||
|
message: 'Deployment failed!'
|
||||||
|
}
|
||||||
|
|
||||||
|
@Security('bearerAuth')
|
||||||
|
@Route('SASjsApi/drive')
|
||||||
|
@Tags('Drive')
|
||||||
|
export default 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)
|
||||||
|
@Post('/deploy')
|
||||||
|
public async deploy(@Body() body: DeployPayload): Promise<DeployResponse> {
|
||||||
|
return deploy(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deploy = async (data: DeployPayload) => {
|
||||||
|
if (!isFileTree(data.fileTree)) {
|
||||||
|
throw { code: 400, ...invalidFormatResponse }
|
||||||
|
}
|
||||||
|
|
||||||
|
await createFileTree(
|
||||||
|
data.fileTree.members,
|
||||||
|
data.appLoc ? data.appLoc.replace(/^\//, '').split('/') : []
|
||||||
|
).catch((err) => {
|
||||||
|
throw { code: 500, ...execErrorResponse, ...err }
|
||||||
|
})
|
||||||
|
|
||||||
|
return successResponse
|
||||||
|
}
|
||||||
@@ -1,35 +1,18 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { createFileTree, getTreeExample } from '../../controllers'
|
import DriveController from '../../controllers/drive'
|
||||||
import { isFileTree } from '../../types'
|
|
||||||
|
|
||||||
const driveRouter = express.Router()
|
const driveRouter = express.Router()
|
||||||
|
|
||||||
driveRouter.post('/deploy', async (req, res) => {
|
driveRouter.post('/deploy', async (req, res) => {
|
||||||
if (!isFileTree(req.body.fileTree)) {
|
const controller = new DriveController()
|
||||||
res.status(400).send({
|
try {
|
||||||
status: 'failure',
|
const response = await controller.deploy(req.body)
|
||||||
message: 'Provided not supported data format.',
|
res.send(response)
|
||||||
example: getTreeExample()
|
} catch (err: any) {
|
||||||
})
|
const statusCode = err.code
|
||||||
|
delete err.code
|
||||||
return
|
res.status(statusCode).send(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
await createFileTree(
|
|
||||||
req.body.fileTree.members,
|
|
||||||
req.body.appLoc ? req.body.appLoc.replace(/^\//, '').split('/') : []
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
res.status(200).send({
|
|
||||||
status: 'success',
|
|
||||||
message: 'Files deployed successfully to @sasjs/server.'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
res
|
|
||||||
.status(500)
|
|
||||||
.send({ status: 'failure', message: 'Deployment failed!', ...err })
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export default driveRouter
|
export default driveRouter
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ router.use(
|
|||||||
swaggerUi.serve,
|
swaggerUi.serve,
|
||||||
swaggerUi.setup(undefined, {
|
swaggerUi.setup(undefined, {
|
||||||
swaggerOptions: {
|
swaggerOptions: {
|
||||||
url: '/swagger.json'
|
url: '/swagger.yaml'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { folderExists, fileExists, readFile, deleteFolder } from '@sasjs/utils'
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { generateAccessToken } from '../../../controllers/auth'
|
import { generateAccessToken } from '../../../controllers/auth'
|
||||||
import { saveTokensInDB } from '../../../utils'
|
import { saveTokensInDB } from '../../../utils'
|
||||||
|
import { FolderMember, ServiceMember } from '../../../types'
|
||||||
|
|
||||||
const clientId = 'someclientID'
|
const clientId = 'someclientID'
|
||||||
const user = {
|
const user = {
|
||||||
@@ -135,21 +136,20 @@ describe('files', () => {
|
|||||||
)
|
)
|
||||||
await expect(folderExists(testJobFolder)).resolves.toEqual(true)
|
await expect(folderExists(testJobFolder)).resolves.toEqual(true)
|
||||||
|
|
||||||
const testJobFile =
|
const exampleService = getExampleService()
|
||||||
path.join(
|
const testJobFile = path.join(testJobFolder, exampleService.name) + '.sas'
|
||||||
testJobFolder,
|
|
||||||
getTreeExample().members[0].members[0].members[0].name
|
|
||||||
) + '.sas'
|
|
||||||
|
|
||||||
console.log(`[testJobFile]`, testJobFile)
|
console.log(`[testJobFile]`, testJobFile)
|
||||||
|
|
||||||
await expect(fileExists(testJobFile)).resolves.toEqual(true)
|
await expect(fileExists(testJobFile)).resolves.toEqual(true)
|
||||||
|
|
||||||
await expect(readFile(testJobFile)).resolves.toEqual(
|
await expect(readFile(testJobFile)).resolves.toEqual(exampleService.code)
|
||||||
getTreeExample().members[0].members[0].members[0].code
|
|
||||||
)
|
|
||||||
|
|
||||||
await deleteFolder(getTmpFilesFolderPath())
|
await deleteFolder(getTmpFilesFolderPath())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const getExampleService = (): ServiceMember =>
|
||||||
|
((getTreeExample().members[0] as FolderMember).members[0] as FolderMember)
|
||||||
|
.members[0] as ServiceMember
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export interface FileTree {
|
export interface FileTree {
|
||||||
members: [FolderMember, ServiceMember]
|
members: (FolderMember | ServiceMember)[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MemberType {
|
export enum MemberType {
|
||||||
@@ -10,7 +10,7 @@ export enum MemberType {
|
|||||||
export interface FolderMember {
|
export interface FolderMember {
|
||||||
name: string
|
name: string
|
||||||
type: MemberType.folder
|
type: MemberType.folder
|
||||||
members: [FolderMember, ServiceMember]
|
members: (FolderMember | ServiceMember)[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServiceMember {
|
export interface ServiceMember {
|
||||||
|
|||||||
Reference in New Issue
Block a user