mirror of
https://github.com/sasjs/server.git
synced 2025-12-12 11:54:35 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adc5aca0f0 | ||
|
|
71c6be6b84 | ||
|
|
9c751877d1 | ||
|
|
2204d54cd6 | ||
|
|
f4eb75ff34 | ||
|
|
a3cde343b7 | ||
|
|
7a70d40dbf | ||
|
|
d27e070fc8 | ||
|
|
27e260e6a4 | ||
|
|
2796db8ead | ||
|
|
84f7c2ab89 | ||
|
|
e68090181a | ||
|
|
d2956fc641 | ||
|
|
a701bb25e7 | ||
|
|
5758bcd392 | ||
|
|
9e53470947 | ||
|
|
81f6605249 | ||
|
|
0b45402946 | ||
|
|
9ac3191891 | ||
|
|
cd00aa2af8 | ||
|
|
0147bcb701 |
46
CHANGELOG.md
46
CHANGELOG.md
@@ -2,6 +2,52 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [0.0.42](https://github.com/sasjs/server/compare/v0.0.41...v0.0.42) (2022-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* execute api, webout as raw ([9c75187](https://github.com/sasjs/server/commit/9c751877d1ed0d0677aff816169a1df7c34c6bf5))
|
||||||
|
|
||||||
|
### [0.0.41](https://github.com/sasjs/server/compare/v0.0.40...v0.0.41) (2022-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **scroll:** closes [#100](https://github.com/sasjs/server/issues/100) ([f4eb75f](https://github.com/sasjs/server/commit/f4eb75ff347e78ac334e55ee26fbdd247bb8eaa2))
|
||||||
|
|
||||||
|
### [0.0.40](https://github.com/sasjs/server/compare/v0.0.39...v0.0.40) (2022-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **deploy:** validating empty file or service in filetree ([27e260e](https://github.com/sasjs/server/commit/27e260e6a453e9978830db63ab669bd48c029897))
|
||||||
|
* macros available for SAS ([7a70d40](https://github.com/sasjs/server/commit/7a70d40dbf0cd91cb3af156755f10006b860f917))
|
||||||
|
* moved macros from codebase to drive ([d27e070](https://github.com/sasjs/server/commit/d27e070fc83894854278df22a8223b8016a1f5f7))
|
||||||
|
|
||||||
|
### [0.0.39](https://github.com/sasjs/server/compare/v0.0.38...v0.0.39) (2022-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* included sasjs core macros at compile time ([e680901](https://github.com/sasjs/server/commit/e68090181acd844f86f3e81153cb5a4e3f4a307f))
|
||||||
|
|
||||||
|
### [0.0.38](https://github.com/sasjs/server/compare/v0.0.37...v0.0.38) (2022-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* quick fix for executables ([9e53470](https://github.com/sasjs/server/commit/9e53470947350f4b8d835a2cb6b70e3dabf247c4))
|
||||||
|
|
||||||
|
### [0.0.37](https://github.com/sasjs/server/compare/v0.0.36...v0.0.37) (2022-03-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* appStream html view ([cd00aa2](https://github.com/sasjs/server/commit/cd00aa2af8c7e0df851050a02152dfeddaec7b0f))
|
||||||
|
* moved macros from codebase to drive ([9ac3191](https://github.com/sasjs/server/commit/9ac3191891bf53ff07135ccec6ddc83b34ea871a))
|
||||||
|
* **webin:** closes [#99](https://github.com/sasjs/server/issues/99) ([0147bcb](https://github.com/sasjs/server/commit/0147bcb701a209266144147a3746baf1eb1ccc63))
|
||||||
|
|
||||||
### [0.0.36](https://github.com/sasjs/server/compare/v0.0.35...v0.0.36) (2022-03-21)
|
### [0.0.36](https://github.com/sasjs/server/compare/v0.0.35...v0.0.36) (2022-03-21)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"assets": [
|
"assets": [
|
||||||
"./build/public/**/*",
|
"./build/public/**/*",
|
||||||
"./build/sasjsbuild/**/*",
|
"./build/sasjsbuild/**/*",
|
||||||
|
"./build/sasjscore/**/*",
|
||||||
"./web/build/**/*"
|
"./web/build/**/*"
|
||||||
],
|
],
|
||||||
"targets": [
|
"targets": [
|
||||||
@@ -91,7 +92,7 @@
|
|||||||
},
|
},
|
||||||
"nodemonConfig": {
|
"nodemonConfig": {
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"tmp/appStreamConfig.json"
|
"tmp/**/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ components:
|
|||||||
$ref: '#/components/schemas/FolderMember'
|
$ref: '#/components/schemas/FolderMember'
|
||||||
-
|
-
|
||||||
$ref: '#/components/schemas/ServiceMember'
|
$ref: '#/components/schemas/ServiceMember'
|
||||||
|
-
|
||||||
|
$ref: '#/components/schemas/FileMember'
|
||||||
type: array
|
type: array
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
@@ -172,19 +174,29 @@ components:
|
|||||||
enum:
|
enum:
|
||||||
- service
|
- service
|
||||||
type: string
|
type: string
|
||||||
MemberType.file:
|
|
||||||
enum:
|
|
||||||
- file
|
|
||||||
type: string
|
|
||||||
ServiceMember:
|
ServiceMember:
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
anyOf:
|
|
||||||
-
|
|
||||||
$ref: '#/components/schemas/MemberType.service'
|
$ref: '#/components/schemas/MemberType.service'
|
||||||
-
|
code:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- type
|
||||||
|
- code
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
MemberType.file:
|
||||||
|
enum:
|
||||||
|
- file
|
||||||
|
type: string
|
||||||
|
FileMember:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
$ref: '#/components/schemas/MemberType.file'
|
$ref: '#/components/schemas/MemberType.file'
|
||||||
code:
|
code:
|
||||||
type: string
|
type: string
|
||||||
@@ -203,6 +215,8 @@ components:
|
|||||||
$ref: '#/components/schemas/FolderMember'
|
$ref: '#/components/schemas/FolderMember'
|
||||||
-
|
-
|
||||||
$ref: '#/components/schemas/ServiceMember'
|
$ref: '#/components/schemas/ServiceMember'
|
||||||
|
-
|
||||||
|
$ref: '#/components/schemas/FileMember'
|
||||||
type: array
|
type: array
|
||||||
required:
|
required:
|
||||||
- members
|
- members
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { asyncForEach, copy, createFolder, deleteFolder } from '@sasjs/utils'
|
import {
|
||||||
|
asyncForEach,
|
||||||
|
copy,
|
||||||
|
createFile,
|
||||||
|
createFolder,
|
||||||
|
deleteFolder,
|
||||||
|
listFilesInFolder
|
||||||
|
} from '@sasjs/utils'
|
||||||
|
|
||||||
import { apiRoot, sasJSCoreMacros } from '../src/utils'
|
import { apiRoot, sasJSCoreMacros, sasJSCoreMacrosInfo } from '../src/utils'
|
||||||
|
|
||||||
const macroCorePath = path.join(apiRoot, 'node_modules', '@sasjs', 'core')
|
const macroCorePath = path.join(apiRoot, 'node_modules', '@sasjs', 'core')
|
||||||
|
|
||||||
@@ -16,6 +23,10 @@ export const copySASjsCore = async () => {
|
|||||||
|
|
||||||
await copy(coreSubFolderPath, sasJSCoreMacros)
|
await copy(coreSubFolderPath, sasJSCoreMacros)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const fileNames = await listFilesInFolder(sasJSCoreMacros)
|
||||||
|
|
||||||
|
await createFile(sasJSCoreMacrosInfo, fileNames.join('\n'))
|
||||||
}
|
}
|
||||||
|
|
||||||
copySASjsCore()
|
copySASjsCore()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import cors from 'cors'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
connectDB,
|
connectDB,
|
||||||
|
copySASjsCore,
|
||||||
getWebBuildFolderPath,
|
getWebBuildFolderPath,
|
||||||
loadAppStreamConfig,
|
loadAppStreamConfig,
|
||||||
sasJSCoreMacros,
|
sasJSCoreMacros,
|
||||||
@@ -42,6 +43,8 @@ const onError: ErrorRequestHandler = (err, req, res, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default setProcessVariables().then(async () => {
|
export default setProcessVariables().then(async () => {
|
||||||
|
await copySASjsCore()
|
||||||
|
|
||||||
// loading these modules after setting up variables due to
|
// loading these modules after setting up variables due to
|
||||||
// multer's usage of process var process.driveLoc
|
// multer's usage of process var process.driveLoc
|
||||||
const { setupRoutes } = await import('./routes/setupRoutes')
|
const { setupRoutes } = await import('./routes/setupRoutes')
|
||||||
@@ -53,8 +56,6 @@ export default setProcessVariables().then(async () => {
|
|||||||
// index.html needs to be injected with some js script.
|
// index.html needs to be injected with some js script.
|
||||||
app.use(express.static(getWebBuildFolderPath()))
|
app.use(express.static(getWebBuildFolderPath()))
|
||||||
|
|
||||||
console.log('sasJSCoreMacros', sasJSCoreMacros)
|
|
||||||
|
|
||||||
app.use(onError)
|
app.use(onError)
|
||||||
|
|
||||||
await connectDB()
|
await connectDB()
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import {
|
|||||||
extractHeaders,
|
extractHeaders,
|
||||||
generateFileUploadSasCode,
|
generateFileUploadSasCode,
|
||||||
getTmpFilesFolderPath,
|
getTmpFilesFolderPath,
|
||||||
|
getTmpMacrosPath,
|
||||||
HTTPHeaders,
|
HTTPHeaders,
|
||||||
isDebugOn,
|
isDebugOn
|
||||||
sasJSCoreMacros
|
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
|
|
||||||
export interface ExecutionVars {
|
export interface ExecutionVars {
|
||||||
@@ -106,7 +106,7 @@ export class ExecutionController {
|
|||||||
`
|
`
|
||||||
|
|
||||||
program = `
|
program = `
|
||||||
options insert=(SASAUTOS="${sasJSCoreMacros}");
|
options insert=(SASAUTOS="${getTmpMacrosPath()}");
|
||||||
|
|
||||||
/* runtime vars */
|
/* runtime vars */
|
||||||
${varStatments}
|
${varStatments}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { MemberType, FolderMember, ServiceMember, FileTree } from '../../types'
|
import {
|
||||||
|
MemberType,
|
||||||
|
FolderMember,
|
||||||
|
ServiceMember,
|
||||||
|
FileTree,
|
||||||
|
FileMember
|
||||||
|
} 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'
|
||||||
|
|
||||||
// REFACTOR: export FileTreeCpntroller
|
// REFACTOR: export FileTreeCpntroller
|
||||||
export const createFileTree = async (
|
export const createFileTree = async (
|
||||||
members: (FolderMember | ServiceMember)[],
|
members: (FolderMember | ServiceMember | FileMember)[],
|
||||||
parentFolders: string[] = []
|
parentFolders: string[] = []
|
||||||
) => {
|
) => {
|
||||||
const destinationPath = path.join(
|
const destinationPath = path.join(
|
||||||
@@ -13,7 +19,9 @@ export const createFileTree = async (
|
|||||||
path.join(...parentFolders)
|
path.join(...parentFolders)
|
||||||
)
|
)
|
||||||
|
|
||||||
await asyncForEach(members, async (member: FolderMember | ServiceMember) => {
|
await asyncForEach(
|
||||||
|
members,
|
||||||
|
async (member: FolderMember | ServiceMember | FileMember) => {
|
||||||
let name = member.name
|
let name = member.name
|
||||||
|
|
||||||
if (member.type === MemberType.service) name += '.sas'
|
if (member.type === MemberType.service) name += '.sas'
|
||||||
@@ -35,7 +43,8 @@ export const createFileTree = async (
|
|||||||
encoding
|
encoding
|
||||||
).catch((err) => Promise.reject({ error: err, failedToCreate: name }))
|
).catch((err) => Promise.reject({ error: err, failedToCreate: name }))
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const style = `<style>
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.app-container .app {
|
.app-container .app {
|
||||||
width: 100px;
|
width: 150px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 10px 10px 0 0;
|
border-radius: 10px 10px 0 0;
|
||||||
@@ -19,6 +19,7 @@ const style = `<style>
|
|||||||
}
|
}
|
||||||
.app-container .app img{
|
.app-container .app img{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
</style>`
|
</style>`
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,28 @@
|
|||||||
export interface FileTree {
|
export enum MemberType {
|
||||||
members: (FolderMember | ServiceMember)[]
|
service = 'service',
|
||||||
|
file = 'file',
|
||||||
|
folder = 'folder'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MemberType {
|
export interface ServiceMember {
|
||||||
folder = 'folder',
|
name: string
|
||||||
service = 'service',
|
type: MemberType.service
|
||||||
file = 'file'
|
code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileMember {
|
||||||
|
name: string
|
||||||
|
type: MemberType.file
|
||||||
|
code: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FolderMember {
|
export interface FolderMember {
|
||||||
name: string
|
name: string
|
||||||
type: MemberType.folder
|
type: MemberType.folder
|
||||||
members: (FolderMember | ServiceMember)[]
|
members: (FolderMember | ServiceMember | FileMember)[]
|
||||||
}
|
}
|
||||||
|
export interface FileTree {
|
||||||
export interface ServiceMember {
|
members: (FolderMember | ServiceMember | FileMember)[]
|
||||||
name: string
|
|
||||||
type: MemberType.service | MemberType.file
|
|
||||||
code: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isFileTree = (arg: any): arg is FileTree =>
|
export const isFileTree = (arg: any): arg is FileTree =>
|
||||||
@@ -25,11 +30,25 @@ export const isFileTree = (arg: any): arg is FileTree =>
|
|||||||
arg.members &&
|
arg.members &&
|
||||||
Array.isArray(arg.members) &&
|
Array.isArray(arg.members) &&
|
||||||
arg.members.filter(
|
arg.members.filter(
|
||||||
(member: FolderMember | ServiceMember) =>
|
(member: ServiceMember | FileMember | FolderMember) =>
|
||||||
!isFolderMember(member) && !isServiceMember(member)
|
!isServiceMember(member, '-') &&
|
||||||
|
!isFileMember(member, '-') &&
|
||||||
|
!isFolderMember(member, '-')
|
||||||
).length === 0
|
).length === 0
|
||||||
|
|
||||||
const isFolderMember = (arg: any): arg is FolderMember =>
|
const isServiceMember = (arg: any, pre: string): arg is ServiceMember =>
|
||||||
|
arg &&
|
||||||
|
typeof arg.name === 'string' &&
|
||||||
|
arg.type === MemberType.service &&
|
||||||
|
typeof arg.code === 'string'
|
||||||
|
|
||||||
|
const isFileMember = (arg: any, pre: string): arg is ServiceMember =>
|
||||||
|
arg &&
|
||||||
|
typeof arg.name === 'string' &&
|
||||||
|
arg.type === MemberType.file &&
|
||||||
|
typeof arg.code === 'string'
|
||||||
|
|
||||||
|
const isFolderMember = (arg: any, pre: string): arg is FolderMember =>
|
||||||
arg &&
|
arg &&
|
||||||
typeof arg.name === 'string' &&
|
typeof arg.name === 'string' &&
|
||||||
arg.type === MemberType.folder &&
|
arg.type === MemberType.folder &&
|
||||||
@@ -37,21 +56,7 @@ const isFolderMember = (arg: any): arg is FolderMember =>
|
|||||||
Array.isArray(arg.members) &&
|
Array.isArray(arg.members) &&
|
||||||
arg.members.filter(
|
arg.members.filter(
|
||||||
(member: FolderMember | ServiceMember) =>
|
(member: FolderMember | ServiceMember) =>
|
||||||
!isFolderMember(member) &&
|
!isServiceMember(member, pre + '-') &&
|
||||||
!isServiceMember(member) &&
|
!isFileMember(member, pre + '-') &&
|
||||||
!isFileMember(member)
|
!isFolderMember(member, pre + '-')
|
||||||
).length === 0
|
).length === 0
|
||||||
|
|
||||||
const isServiceMember = (arg: any): arg is ServiceMember =>
|
|
||||||
arg &&
|
|
||||||
typeof arg.name === 'string' &&
|
|
||||||
arg.type === MemberType.service &&
|
|
||||||
arg.code &&
|
|
||||||
typeof arg.code === 'string'
|
|
||||||
|
|
||||||
const isFileMember = (arg: any): arg is ServiceMember =>
|
|
||||||
arg &&
|
|
||||||
typeof arg.name === 'string' &&
|
|
||||||
arg.type === MemberType.file &&
|
|
||||||
arg.code &&
|
|
||||||
typeof arg.code === 'string'
|
|
||||||
|
|||||||
32
api/src/utils/copySASjsCore.ts
Normal file
32
api/src/utils/copySASjsCore.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import {
|
||||||
|
asyncForEach,
|
||||||
|
createFile,
|
||||||
|
createFolder,
|
||||||
|
deleteFolder,
|
||||||
|
readFile
|
||||||
|
} from '@sasjs/utils'
|
||||||
|
|
||||||
|
import { getTmpMacrosPath, sasJSCoreMacros, sasJSCoreMacrosInfo } from '.'
|
||||||
|
|
||||||
|
export const copySASjsCore = async () => {
|
||||||
|
console.log('Copying Macros from container to drive(tmp).')
|
||||||
|
|
||||||
|
const macrosDrivePath = getTmpMacrosPath()
|
||||||
|
|
||||||
|
await deleteFolder(macrosDrivePath)
|
||||||
|
await createFolder(macrosDrivePath)
|
||||||
|
|
||||||
|
const macros = await readFile(sasJSCoreMacrosInfo)
|
||||||
|
|
||||||
|
await asyncForEach(macros.split('\n'), async (macroName) => {
|
||||||
|
const macroFileSourcePath = path.join(sasJSCoreMacros, macroName)
|
||||||
|
const macroContent = await readFile(macroFileSourcePath)
|
||||||
|
|
||||||
|
const macroFileDestPath = path.join(macrosDrivePath, macroName)
|
||||||
|
|
||||||
|
await createFile(macroFileDestPath, macroContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('Macros Drive Path:', macrosDrivePath)
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ export const sysInitCompiledPath = path.join(
|
|||||||
)
|
)
|
||||||
|
|
||||||
export const sasJSCoreMacros = path.join(apiRoot, 'sasjscore')
|
export const sasJSCoreMacros = path.join(apiRoot, 'sasjscore')
|
||||||
|
export const sasJSCoreMacrosInfo = path.join(apiRoot, 'sasjscore', '.macrolist')
|
||||||
|
|
||||||
export const getWebBuildFolderPath = () =>
|
export const getWebBuildFolderPath = () =>
|
||||||
path.join(codebaseRoot, 'web', 'build')
|
path.join(codebaseRoot, 'web', 'build')
|
||||||
@@ -18,6 +19,8 @@ export const getTmpFolderPath = () => process.driveLoc
|
|||||||
export const getTmpAppStreamConfigPath = () =>
|
export const getTmpAppStreamConfigPath = () =>
|
||||||
path.join(getTmpFolderPath(), 'appStreamConfig.json')
|
path.join(getTmpFolderPath(), 'appStreamConfig.json')
|
||||||
|
|
||||||
|
export const getTmpMacrosPath = () => path.join(getTmpFolderPath(), 'sasjscore')
|
||||||
|
|
||||||
export const getTmpUploadsPath = () => path.join(getTmpFolderPath(), 'uploads')
|
export const getTmpUploadsPath = () => path.join(getTmpFolderPath(), 'uploads')
|
||||||
|
|
||||||
export const getTmpFilesFolderPath = () =>
|
export const getTmpFilesFolderPath = () =>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
export * from './appStreamConfig'
|
export * from './appStreamConfig'
|
||||||
export * from './connectDB'
|
export * from './connectDB'
|
||||||
|
export * from './copySASjsCore'
|
||||||
export * from './extractHeaders'
|
export * from './extractHeaders'
|
||||||
export * from './file'
|
export * from './file'
|
||||||
export * from './generateAccessToken'
|
export * from './generateAccessToken'
|
||||||
export * from './generateAuthCode'
|
export * from './generateAuthCode'
|
||||||
export * from './generateRefreshToken'
|
export * from './generateRefreshToken'
|
||||||
export * from './isDebugOn'
|
|
||||||
export * from './getCertificates'
|
export * from './getCertificates'
|
||||||
export * from './getDesktopFields'
|
export * from './getDesktopFields'
|
||||||
|
export * from './isDebugOn'
|
||||||
export * from './parseLogToArray'
|
export * from './parseLogToArray'
|
||||||
export * from './removeTokensInDB'
|
export * from './removeTokensInDB'
|
||||||
export * from './saveTokensInDB'
|
export * from './saveTokensInDB'
|
||||||
|
|||||||
@@ -1,9 +1,21 @@
|
|||||||
import path from 'path'
|
|
||||||
import fs from 'fs'
|
|
||||||
import { getTmpSessionsFolderPath } from '.'
|
|
||||||
import { MulterFile } from '../types/Upload'
|
import { MulterFile } from '../types/Upload'
|
||||||
import { listFilesInFolder } from '@sasjs/utils'
|
import { listFilesInFolder } from '@sasjs/utils'
|
||||||
|
|
||||||
|
interface FilenameMapSingle {
|
||||||
|
fieldName: string
|
||||||
|
originalName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FilenamesMap {
|
||||||
|
[key: string]: FilenameMapSingle
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UploadedFiles extends FilenameMapSingle {
|
||||||
|
fileref: string
|
||||||
|
filepath: string
|
||||||
|
count: number
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It will create an object that maps hashed file names to the original names
|
* It will create an object that maps hashed file names to the original names
|
||||||
* @param files array of files to be mapped
|
* @param files array of files to be mapped
|
||||||
@@ -12,10 +24,13 @@ import { listFilesInFolder } from '@sasjs/utils'
|
|||||||
export const makeFilesNamesMap = (files: MulterFile[]) => {
|
export const makeFilesNamesMap = (files: MulterFile[]) => {
|
||||||
if (!files) return null
|
if (!files) return null
|
||||||
|
|
||||||
const filesNamesMap: { [key: string]: string } = {}
|
const filesNamesMap: FilenamesMap = {}
|
||||||
|
|
||||||
for (let file of files) {
|
for (let file of files) {
|
||||||
filesNamesMap[file.filename] = file.originalname
|
filesNamesMap[file.filename] = {
|
||||||
|
fieldName: file.fieldname,
|
||||||
|
originalName: file.originalname
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filesNamesMap
|
return filesNamesMap
|
||||||
@@ -28,17 +43,12 @@ export const makeFilesNamesMap = (files: MulterFile[]) => {
|
|||||||
* @returns generated sas code
|
* @returns generated sas code
|
||||||
*/
|
*/
|
||||||
export const generateFileUploadSasCode = async (
|
export const generateFileUploadSasCode = async (
|
||||||
filesNamesMap: any,
|
filesNamesMap: FilenamesMap,
|
||||||
sasSessionFolder: string
|
sasSessionFolder: string
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
let uploadSasCode = ''
|
let uploadSasCode = ''
|
||||||
let fileCount = 0
|
let fileCount = 0
|
||||||
let uploadedFilesMap: {
|
const uploadedFiles: UploadedFiles[] = []
|
||||||
fileref: string
|
|
||||||
filepath: string
|
|
||||||
filename: string
|
|
||||||
count: number
|
|
||||||
}[] = []
|
|
||||||
|
|
||||||
const sasSessionFolderList: string[] = await listFilesInFolder(
|
const sasSessionFolderList: string[] = await listFilesInFolder(
|
||||||
sasSessionFolder
|
sasSessionFolder
|
||||||
@@ -50,31 +60,32 @@ export const generateFileUploadSasCode = async (
|
|||||||
if (fileName.includes('req_file')) {
|
if (fileName.includes('req_file')) {
|
||||||
fileCount++
|
fileCount++
|
||||||
|
|
||||||
uploadedFilesMap.push({
|
uploadedFiles.push({
|
||||||
fileref: `_sjs${fileCountString}`,
|
fileref: `_sjs${fileCountString}`,
|
||||||
filepath: `${sasSessionFolder}/${fileName}`,
|
filepath: `${sasSessionFolder}/${fileName}`,
|
||||||
filename: filesNamesMap[fileName],
|
originalName: filesNamesMap[fileName].originalName,
|
||||||
|
fieldName: filesNamesMap[fileName].fieldName,
|
||||||
count: fileCount
|
count: fileCount
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
for (let uploadedMap of uploadedFilesMap) {
|
for (const uploadedFile of uploadedFiles) {
|
||||||
uploadSasCode += `\nfilename ${uploadedMap.fileref} "${uploadedMap.filepath}";`
|
uploadSasCode += `\nfilename ${uploadedFile.fileref} "${uploadedFile.filepath}";`
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadSasCode += `\n%let _WEBIN_FILE_COUNT=${fileCount};`
|
uploadSasCode += `\n%let _WEBIN_FILE_COUNT=${fileCount};`
|
||||||
|
|
||||||
for (let uploadedMap of uploadedFilesMap) {
|
for (const uploadedFile of uploadedFiles) {
|
||||||
uploadSasCode += `\n%let _WEBIN_FILENAME${uploadedMap.count}=${uploadedMap.filename};`
|
uploadSasCode += `\n%let _WEBIN_FILENAME${uploadedFile.count}=${uploadedFile.originalName};`
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let uploadedMap of uploadedFilesMap) {
|
for (const uploadedFile of uploadedFiles) {
|
||||||
uploadSasCode += `\n%let _WEBIN_FILEREF${uploadedMap.count}=${uploadedMap.fileref};`
|
uploadSasCode += `\n%let _WEBIN_FILEREF${uploadedFile.count}=${uploadedFile.fileref};`
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let uploadedMap of uploadedFilesMap) {
|
for (const uploadedFile of uploadedFiles) {
|
||||||
uploadSasCode += `\n%let _WEBIN_NAME${uploadedMap.count}=${uploadedMap.filepath};`
|
uploadSasCode += `\n%let _WEBIN_NAME${uploadedFile.count}=${uploadedFile.fieldName};`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileCount > 0) {
|
if (fileCount > 0) {
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.36",
|
"version": "0.0.42",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.36",
|
"version": "0.0.42",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
"standard-version": "^9.3.2"
|
"standard-version": "^9.3.2"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.36",
|
"version": "0.0.42",
|
||||||
"description": "NodeJS wrapper for calling the SAS binary executable",
|
"description": "NodeJS wrapper for calling the SAS binary executable",
|
||||||
"repository": "https://github.com/sasjs/server",
|
"repository": "https://github.com/sasjs/server",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
### testing upload file example
|
### testing upload file example
|
||||||
POST http://localhost:5000/SASjsApi/stp/execute/?_program=/Public/app/viya/services/editors/loadfile&table=DCCONFIG.MPE_X_TEST
|
POST http://localhost:5000/SASjsApi/stp/execute/?_program=/Public/app/viya/services/editors/loadfile&table=DCCONFIG.MPE_X_TEST
|
||||||
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarynkYOqevUMKZrXeAy
|
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarynkYOqevUMKZrXeAy
|
||||||
|
|
||||||
------WebKitFormBoundarynkYOqevUMKZrXeAy
|
------WebKitFormBoundarynkYOqevUMKZrXeAy
|
||||||
Content-Disposition: form-data; name="file"; filename="DCCONFIG.MPE_X_TEST.xlsx"
|
Content-Disposition: form-data; name="fileSome11"; filename="DCCONFIG.MPE_X_TEST.xlsx"
|
||||||
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||||
|
|
||||||
|
|
||||||
------WebKitFormBoundarynkYOqevUMKZrXeAy
|
------WebKitFormBoundarynkYOqevUMKZrXeAy
|
||||||
Content-Disposition: form-data; name="file"; filename="DCCONFIG.MPE_X_TEST.xlsx.csv"
|
Content-Disposition: form-data; name="fileSome22"; filename="DCCONFIG.MPE_X_TEST.xlsx.csv"
|
||||||
Content-Type: application/csv
|
Content-Type: application/csv
|
||||||
|
|
||||||
_____DELETE__THIS__RECORD_____,PRIMARY_KEY_FIELD,SOME_CHAR,SOME_DROPDOWN,SOME_NUM,SOME_DATE,SOME_DATETIME,SOME_TIME,SOME_SHORTNUM,SOME_BESTNUM
|
_____DELETE__THIS__RECORD_____,PRIMARY_KEY_FIELD,SOME_CHAR,SOME_DROPDOWN,SOME_NUM,SOME_DATE,SOME_DATETIME,SOME_TIME,SOME_SHORTNUM,SOME_BESTNUM
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ const Studio = () => {
|
|||||||
|
|
||||||
let weboutString: string
|
let weboutString: string
|
||||||
try {
|
try {
|
||||||
weboutString = res.data.webout
|
weboutString = res.data._webout
|
||||||
.split('>>weboutBEGIN<<')[1]
|
.split('>>weboutBEGIN<<')[1]
|
||||||
.split('>>weboutEND<<')[0]
|
.split('>>weboutEND<<')[0]
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
weboutString = res?.data?.webout ?? ''
|
weboutString = res?.data?._webout ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
let webout: string
|
let webout: string
|
||||||
@@ -70,6 +70,9 @@ const Studio = () => {
|
|||||||
|
|
||||||
setWebout(`<pre><code>${webout}</code></pre>`)
|
setWebout(`<pre><code>${webout}</code></pre>`)
|
||||||
setTab('2')
|
setTab('2')
|
||||||
|
|
||||||
|
// Scroll to bottom of log
|
||||||
|
window.scrollTo(0, document.body.scrollHeight)
|
||||||
})
|
})
|
||||||
.catch((err) => console.log(err))
|
.catch((err) => console.log(err))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user