@things-factory/board-service 8.0.0 → 9.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/controllers/headless-pdf-to-image.js +7 -2
- package/dist-server/controllers/headless-pdf-to-image.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/views/internal-board-full-feature-view.html +1 -1
- package/server/constants/error-code.ts +0 -2
- package/server/controllers/analyzer/analyze-integration.ts +0 -142
- package/server/controllers/fonts.ts +0 -83
- package/server/controllers/headless-model.ts +0 -53
- package/server/controllers/headless-pdf-to-image.ts +0 -103
- package/server/controllers/headless-playlist.ts +0 -71
- package/server/controllers/headless-pool-for-board.ts +0 -71
- package/server/controllers/headless-pool-for-label.ts +0 -141
- package/server/controllers/index.ts +0 -11
- package/server/controllers/label-command.ts +0 -62
- package/server/controllers/pdf.ts +0 -132
- package/server/controllers/screenshot.ts +0 -127
- package/server/controllers/thumbnail.ts +0 -18
- package/server/errors/index.ts +0 -1
- package/server/errors/license-error.ts +0 -21
- package/server/index.ts +0 -36
- package/server/migrations/1556862253000-SeedGroup.ts +0 -51
- package/server/migrations/index.ts +0 -9
- package/server/routers/internal-board-view-router.ts +0 -33
- package/server/routers/standalone-board-service-router.ts +0 -326
- package/server/routes.ts +0 -25
- package/server/service/analysis/analysis-query.ts +0 -13
- package/server/service/analysis/index.ts +0 -3
- package/server/service/board/board-history.ts +0 -137
- package/server/service/board/board-mutation.ts +0 -446
- package/server/service/board/board-query.ts +0 -180
- package/server/service/board/board-subscription.ts +0 -43
- package/server/service/board/board-type.ts +0 -58
- package/server/service/board/board.ts +0 -125
- package/server/service/board/event-subscriber.ts +0 -68
- package/server/service/board/index.ts +0 -10
- package/server/service/board-favorite/board-favorite-query.ts +0 -53
- package/server/service/board-favorite/board-favorite-type.ts +0 -18
- package/server/service/board-favorite/index.ts +0 -4
- package/server/service/board-template/board-template-mutation.ts +0 -161
- package/server/service/board-template/board-template-query.ts +0 -121
- package/server/service/board-template/board-template-type.ts +0 -53
- package/server/service/board-template/board-template.ts +0 -114
- package/server/service/board-template/index.ts +0 -7
- package/server/service/group/group-mutation.ts +0 -82
- package/server/service/group/group-query.ts +0 -58
- package/server/service/group/group-type.ts +0 -30
- package/server/service/group/group.ts +0 -69
- package/server/service/group/index.ts +0 -6
- package/server/service/index.ts +0 -56
- package/server/service/permission/domain-permission-subscriber.ts +0 -27
- package/server/service/permission/index.ts +0 -3
- package/server/service/play-group/event-subscriber.ts +0 -58
- package/server/service/play-group/index.ts +0 -9
- package/server/service/play-group/play-group-mutation.ts +0 -148
- package/server/service/play-group/play-group-query.ts +0 -92
- package/server/service/play-group/play-group-subscription.ts +0 -43
- package/server/service/play-group/play-group-type.ts +0 -30
- package/server/service/play-group/play-group.ts +0 -74
- package/server/service/theme/index.ts +0 -7
- package/server/service/theme/theme-mutation.ts +0 -128
- package/server/service/theme/theme-query.ts +0 -48
- package/server/service/theme/theme-type.ts +0 -55
- package/server/service/theme/theme.ts +0 -97
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/board-service",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0-beta.3",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"things-factory": true,
|
|
6
6
|
"author": "",
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create ./server/migrations/migration"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@things-factory/auth-base": "^
|
|
27
|
-
"@things-factory/env": "^8.0.0",
|
|
28
|
-
"@things-factory/fav-base": "^
|
|
29
|
-
"@things-factory/font-base": "^
|
|
30
|
-
"@things-factory/integration-base": "^
|
|
26
|
+
"@things-factory/auth-base": "^9.0.0-beta.3",
|
|
27
|
+
"@things-factory/env": "^8.0.0-beta.4",
|
|
28
|
+
"@things-factory/fav-base": "^9.0.0-beta.3",
|
|
29
|
+
"@things-factory/font-base": "^9.0.0-beta.3",
|
|
30
|
+
"@things-factory/integration-base": "^9.0.0-beta.3",
|
|
31
31
|
"@things-factory/operato-license-checker": "^4.0.4",
|
|
32
32
|
"content-disposition": "^0.5.3",
|
|
33
33
|
"generic-pool": "^3.8.2",
|
|
34
34
|
"puppeteer": "^23.0.0"
|
|
35
35
|
},
|
|
36
|
-
"gitHead": "
|
|
36
|
+
"gitHead": "1d7e0dd4c88f3c3f3bd311c00e4b1d1542d53634"
|
|
37
37
|
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import uniq from 'lodash/uniq'
|
|
2
|
-
|
|
3
|
-
import { Domain, getRepository } from '@things-factory/shell'
|
|
4
|
-
import { analyzeIntegration } from '@things-factory/integration-base'
|
|
5
|
-
import { Board } from '../../service/board/board'
|
|
6
|
-
|
|
7
|
-
function findObjectsWithCondition(container, condition: (component: any) => boolean) {
|
|
8
|
-
let result = []
|
|
9
|
-
|
|
10
|
-
if (condition(container)) {
|
|
11
|
-
result.push(container)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (container.components) {
|
|
15
|
-
for (const component of container.components) {
|
|
16
|
-
result = result.concat(findObjectsWithCondition(component, condition))
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return result
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function getRelationsInBoard(board: Board) {
|
|
24
|
-
try {
|
|
25
|
-
const model = JSON.parse(board.model) || {}
|
|
26
|
-
|
|
27
|
-
const scenarioNames = findObjectsWithCondition(model, component => component.scenarioName).map(
|
|
28
|
-
component => component.scenarioName
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
const tags = findObjectsWithCondition(model, component => component.tag).map(component => component.tag)
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
scenarioNames: uniq(scenarioNames.filter(Boolean)),
|
|
35
|
-
tags: uniq(tags.filter(Boolean))
|
|
36
|
-
}
|
|
37
|
-
} catch (err) {
|
|
38
|
-
console.error('analyze-integration::getRelationsInBoard error', err)
|
|
39
|
-
return {
|
|
40
|
-
scenarioNames: [],
|
|
41
|
-
tags: []
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function analyzeBoardIntegration(domain: Domain) {
|
|
47
|
-
const model = await analyzeIntegration(domain)
|
|
48
|
-
|
|
49
|
-
var id = 0
|
|
50
|
-
|
|
51
|
-
const boards = await getRepository(Board).find({
|
|
52
|
-
where: { domain: { id: domain.id } }
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
model.nodes = model.nodes.concat(
|
|
56
|
-
boards.map(board => {
|
|
57
|
-
return {
|
|
58
|
-
id: board.id,
|
|
59
|
-
labels: ['Board'],
|
|
60
|
-
text: board.name,
|
|
61
|
-
icon: 'dashboard',
|
|
62
|
-
properties: {
|
|
63
|
-
name: board.name,
|
|
64
|
-
description: board.description
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
boards.forEach(board => {
|
|
71
|
-
const { scenarioNames, tags } = getRelationsInBoard(board)
|
|
72
|
-
|
|
73
|
-
var scenarioNodes = scenarioNames.map(name =>
|
|
74
|
-
model.nodes.find(node => node.labels.includes('Scenario') && node.properties?.name == name)
|
|
75
|
-
)
|
|
76
|
-
var tagNodes = tags.map(tag => model.nodes.find(node => node.labels.includes('Tag') && node.properties?.tag == tag))
|
|
77
|
-
|
|
78
|
-
const missingScenarioNodes = scenarioNodes
|
|
79
|
-
.filter(node => !node)
|
|
80
|
-
.map((_, i) => scenarioNames[i])
|
|
81
|
-
.map(missingScenario => {
|
|
82
|
-
return {
|
|
83
|
-
id: `missing-scenario-${missingScenario}`,
|
|
84
|
-
labels: ['Scenario'],
|
|
85
|
-
text: missingScenario,
|
|
86
|
-
icon: 'settings',
|
|
87
|
-
properties: {
|
|
88
|
-
name: missingScenario,
|
|
89
|
-
missing: true
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
model.nodes = model.nodes.concat(missingScenarioNodes)
|
|
95
|
-
|
|
96
|
-
const missingTagNodes = tagNodes
|
|
97
|
-
.filter(node => !node)
|
|
98
|
-
.map((_, i) => tags[i])
|
|
99
|
-
.map(missingTag => {
|
|
100
|
-
return {
|
|
101
|
-
id: `missing-tag-${missingTag}`,
|
|
102
|
-
labels: ['Tag'],
|
|
103
|
-
text: missingTag,
|
|
104
|
-
icon: 'label',
|
|
105
|
-
properties: {
|
|
106
|
-
name: missingTag,
|
|
107
|
-
missing: true
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
model.nodes = model.nodes.concat(missingTagNodes)
|
|
113
|
-
|
|
114
|
-
tagNodes.filter(node => !node).map((_, i) => tags[i])
|
|
115
|
-
|
|
116
|
-
var relationships = [...scenarioNodes.filter(Boolean), ...missingScenarioNodes].map(node => {
|
|
117
|
-
return {
|
|
118
|
-
id: `bsce-${++id}`,
|
|
119
|
-
type: 'call',
|
|
120
|
-
startNode: board.id,
|
|
121
|
-
endNode: node.id,
|
|
122
|
-
properties: {}
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
|
|
126
|
-
model.relationships = model.relationships.concat(relationships)
|
|
127
|
-
|
|
128
|
-
relationships = [...tagNodes.filter(Boolean), ...missingTagNodes].map(node => {
|
|
129
|
-
return {
|
|
130
|
-
id: `btag-${++id}`,
|
|
131
|
-
type: 'subscribe',
|
|
132
|
-
startNode: board.id,
|
|
133
|
-
endNode: node.id,
|
|
134
|
-
properties: {}
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
model.relationships = model.relationships.concat(relationships)
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
return model
|
|
142
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { SelectQueryBuilder } from 'typeorm'
|
|
2
|
-
|
|
3
|
-
import { Font } from '@things-factory/font-base'
|
|
4
|
-
import { Attachment } from '@things-factory/attachment-base'
|
|
5
|
-
import { getRepository, Domain } from '@things-factory/shell'
|
|
6
|
-
|
|
7
|
-
export const fonts = async (domain?: Domain) => {
|
|
8
|
-
const qb: SelectQueryBuilder<Font> = await getRepository(Font).createQueryBuilder('FONT')
|
|
9
|
-
|
|
10
|
-
var fonts = domain
|
|
11
|
-
? await qb
|
|
12
|
-
.select('FONT.name', 'name')
|
|
13
|
-
.distinct(true)
|
|
14
|
-
.addSelect('FONT.provider', 'provider')
|
|
15
|
-
.addSelect('FONT.id', 'id')
|
|
16
|
-
.addSelect('FONT.uri', 'uri')
|
|
17
|
-
.where({ domain: { id: domain.id }, active: true })
|
|
18
|
-
.getRawMany()
|
|
19
|
-
: await qb
|
|
20
|
-
.select('FONT.name', 'name')
|
|
21
|
-
.distinct(true)
|
|
22
|
-
.addSelect('FONT.provider', 'provider')
|
|
23
|
-
.addSelect('FONT.id', 'id')
|
|
24
|
-
.addSelect('FONT.uri', 'uri')
|
|
25
|
-
.where({ active: true })
|
|
26
|
-
.getRawMany()
|
|
27
|
-
|
|
28
|
-
var googleFonts = fonts.filter(({ provider }) => provider == 'google')
|
|
29
|
-
var customFonts = fonts.filter(({ provider }) => provider == 'custom')
|
|
30
|
-
|
|
31
|
-
var customFontCSS: string = ''
|
|
32
|
-
|
|
33
|
-
for (const font of customFonts) {
|
|
34
|
-
var files: Attachment[] = domain
|
|
35
|
-
? await getRepository(Attachment).findBy({
|
|
36
|
-
domain: { id: domain.id },
|
|
37
|
-
refBy: font.id
|
|
38
|
-
})
|
|
39
|
-
: await getRepository(Attachment).findBy({
|
|
40
|
-
refBy: font.id
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
if (files && files.length > 0) {
|
|
44
|
-
customFontCSS += files
|
|
45
|
-
.map(file => {
|
|
46
|
-
const { name: filename, fullpath } = file
|
|
47
|
-
const bold = filename.toUpperCase().indexOf('BOLD') !== -1
|
|
48
|
-
|
|
49
|
-
return `@font-face {
|
|
50
|
-
font-family: '${font.name}';
|
|
51
|
-
src: local('${font.name}'), url(${fullpath});
|
|
52
|
-
font-weight: ${bold ? 'bold' : 'normal'};
|
|
53
|
-
}
|
|
54
|
-
`
|
|
55
|
-
})
|
|
56
|
-
.join('\n')
|
|
57
|
-
} else {
|
|
58
|
-
customFontCSS += `@font-face {
|
|
59
|
-
font-family: '${font.name}';
|
|
60
|
-
src: local('${font.name}')${font.uri ? `, url(${font.uri})` : ''};
|
|
61
|
-
}
|
|
62
|
-
`
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return googleFonts.length > 0 || customFonts.length > 0
|
|
67
|
-
? [
|
|
68
|
-
{
|
|
69
|
-
...(googleFonts.length > 0 && {
|
|
70
|
-
google: {
|
|
71
|
-
families: googleFonts.map(({ name }) => name)
|
|
72
|
-
}
|
|
73
|
-
}),
|
|
74
|
-
...(customFonts.length > 0 && {
|
|
75
|
-
custom: {
|
|
76
|
-
families: customFonts.map(({ name }) => name)
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
},
|
|
80
|
-
customFonts.length > 0 ? customFontCSS : null
|
|
81
|
-
]
|
|
82
|
-
: []
|
|
83
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { In } from 'typeorm'
|
|
2
|
-
import { getContextPath, getRepository } from '@things-factory/shell'
|
|
3
|
-
|
|
4
|
-
import { Board } from '../service/board/board'
|
|
5
|
-
import { BoardHistory } from '../service/board/board-history'
|
|
6
|
-
|
|
7
|
-
export const headlessModel = async (target, draft: boolean = false) => {
|
|
8
|
-
var { domain, id, model, name } = target || {}
|
|
9
|
-
|
|
10
|
-
if (model) {
|
|
11
|
-
if (typeof model == 'string') {
|
|
12
|
-
model = JSON.parse(model)
|
|
13
|
-
} else if (typeof model !== 'object') {
|
|
14
|
-
throw 'model should be a string or object'
|
|
15
|
-
}
|
|
16
|
-
} else {
|
|
17
|
-
if (id) {
|
|
18
|
-
var board = await getRepository(Board).findOne({
|
|
19
|
-
where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id }
|
|
20
|
-
})
|
|
21
|
-
} else if (name) {
|
|
22
|
-
var board = await getRepository(Board).findOne({
|
|
23
|
-
where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, name }
|
|
24
|
-
})
|
|
25
|
-
} else {
|
|
26
|
-
throw 'parameter model or id mandatory'
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!draft && board) {
|
|
30
|
-
const latestReleased =
|
|
31
|
-
board.state == 'released'
|
|
32
|
-
? board
|
|
33
|
-
: await getRepository(BoardHistory)
|
|
34
|
-
.createQueryBuilder('history')
|
|
35
|
-
.where('history.originalId = :originalId', { originalId: board.id })
|
|
36
|
-
.orderBy('history.version', 'DESC')
|
|
37
|
-
.limit(1)
|
|
38
|
-
.getOne()
|
|
39
|
-
|
|
40
|
-
model = (latestReleased || board).model
|
|
41
|
-
} else {
|
|
42
|
-
model = board.model
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
model = JSON.parse(model)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
base: getContextPath(domain?.subdomain) + (domain ? '/' : ''),
|
|
50
|
-
model,
|
|
51
|
-
board
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
const puppeteer = require('puppeteer')
|
|
2
|
-
const { Readable } = require('stream')
|
|
3
|
-
const ejs = require('ejs')
|
|
4
|
-
|
|
5
|
-
export const pdfToImage = async ({ pdfPath, fileName, extension = 'png', quality = 2, defaultViewport = null }) => {
|
|
6
|
-
const browser = await puppeteer.launch({
|
|
7
|
-
headless: true,
|
|
8
|
-
args: [
|
|
9
|
-
'--disable-web-security',
|
|
10
|
-
'--disable-features=IsolateOrigins',
|
|
11
|
-
'--disable-site-isolation-trials',
|
|
12
|
-
'--no-sandbox'
|
|
13
|
-
],
|
|
14
|
-
defaultViewport
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const protocol = 'http'
|
|
19
|
-
const host = 'localhost'
|
|
20
|
-
const port = process.env.PORT
|
|
21
|
-
const pdfUrl = `${protocol}://${host}:${port}${pdfPath}`
|
|
22
|
-
|
|
23
|
-
const page = await browser.newPage()
|
|
24
|
-
const html = await ejs.render(getPdfHtmlTemplate(), { data: { pdfUrl, quality } })
|
|
25
|
-
|
|
26
|
-
// 페이지 로딩시 까지 기다리고 스크린샷
|
|
27
|
-
await page.setContent(html, { waitUntil: 'networkidle0' })
|
|
28
|
-
await page.waitForNetworkIdle()
|
|
29
|
-
await page.$('#page')
|
|
30
|
-
const screenshot = await page.screenshot({
|
|
31
|
-
type: extension,
|
|
32
|
-
omitBackground: true
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
// graphql fileupload형태로 return을 위해 stream 생성
|
|
36
|
-
const stream = new Readable()
|
|
37
|
-
stream.push(screenshot)
|
|
38
|
-
stream.push(null)
|
|
39
|
-
|
|
40
|
-
await browser.close()
|
|
41
|
-
|
|
42
|
-
// file upload 형태로 return
|
|
43
|
-
return {
|
|
44
|
-
filename: `${fileName}.${extension}`,
|
|
45
|
-
mimetype: `image/${extension}`,
|
|
46
|
-
encoding: '7bit',
|
|
47
|
-
createReadStream: () => stream
|
|
48
|
-
}
|
|
49
|
-
} catch (e) {
|
|
50
|
-
await browser.close()
|
|
51
|
-
console.log('Error creating thumbnail', e)
|
|
52
|
-
throw new Error('Error creating thumbnail')
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function getPdfHtmlTemplate() {
|
|
57
|
-
return `
|
|
58
|
-
<html lang="en">
|
|
59
|
-
<head>
|
|
60
|
-
<meta charset="UTF-8" />
|
|
61
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
62
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
63
|
-
|
|
64
|
-
<style nonce="<%= nonce %>">
|
|
65
|
-
body {
|
|
66
|
-
width: 100vw;
|
|
67
|
-
height: 100vh;
|
|
68
|
-
margin: 0;
|
|
69
|
-
}
|
|
70
|
-
#page {
|
|
71
|
-
display: flex;
|
|
72
|
-
width: 100%;
|
|
73
|
-
height: 100%;
|
|
74
|
-
}
|
|
75
|
-
</style>
|
|
76
|
-
|
|
77
|
-
</head>
|
|
78
|
-
<body>
|
|
79
|
-
<canvas id="page"></canvas>
|
|
80
|
-
<script src="https://unpkg.com/pdfjs-dist@2.0.489/build/pdf.min.js"></script>
|
|
81
|
-
<script nonce="<%= nonce %>">
|
|
82
|
-
;(async () => {
|
|
83
|
-
const pdf = await pdfjsLib.getDocument('<%= data.pdfUrl %>')
|
|
84
|
-
const page = await pdf.getPage(1)
|
|
85
|
-
const viewport = page.getViewport('<%= data.quality %>')
|
|
86
|
-
const canvas = document.getElementById('page')
|
|
87
|
-
const context = canvas.getContext('2d')
|
|
88
|
-
|
|
89
|
-
canvas.height = viewport.height
|
|
90
|
-
canvas.width = viewport.width
|
|
91
|
-
|
|
92
|
-
const renderContext = {
|
|
93
|
-
canvasContext: context,
|
|
94
|
-
viewport: viewport
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
page.render(renderContext)
|
|
98
|
-
})()
|
|
99
|
-
</script>
|
|
100
|
-
</body>
|
|
101
|
-
</html>
|
|
102
|
-
`
|
|
103
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { getContextPath, getRepository } from '@things-factory/shell'
|
|
2
|
-
|
|
3
|
-
import { PlayGroup } from '../service/play-group/play-group'
|
|
4
|
-
import { BoardHistory } from '../service/board/board-history'
|
|
5
|
-
|
|
6
|
-
export const headlessPlaylist = async (target, draft: boolean = false) => {
|
|
7
|
-
var { domain, id, name } = target || {}
|
|
8
|
-
|
|
9
|
-
if (id || name) {
|
|
10
|
-
const repository = getRepository(PlayGroup)
|
|
11
|
-
|
|
12
|
-
if (id) {
|
|
13
|
-
var playGroup = await repository.findOne({
|
|
14
|
-
where: { domain: { id: domain.id }, id },
|
|
15
|
-
relations: ['boards']
|
|
16
|
-
})
|
|
17
|
-
} else if (name) {
|
|
18
|
-
var playGroup = await repository.findOne({
|
|
19
|
-
where: { domain: { id: domain.id }, name },
|
|
20
|
-
relations: ['boards']
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (!draft && playGroup) {
|
|
25
|
-
const { boards } = playGroup
|
|
26
|
-
for (let board of boards) {
|
|
27
|
-
const latestReleased =
|
|
28
|
-
board.state == 'released'
|
|
29
|
-
? board
|
|
30
|
-
: await getRepository(BoardHistory)
|
|
31
|
-
.createQueryBuilder('history')
|
|
32
|
-
.where('history.originalId = :originalId', { originalId: board.id })
|
|
33
|
-
.orderBy('history.version', 'DESC')
|
|
34
|
-
.limit(1)
|
|
35
|
-
.getOne()
|
|
36
|
-
|
|
37
|
-
if (latestReleased) {
|
|
38
|
-
board.model = latestReleased.model
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
playGroup.boards = playGroup.boards.sort((a, b) => {
|
|
44
|
-
// 배열 A에 포함된 아이디의 순서를 가져옵니다.
|
|
45
|
-
const indexOfOrder = (playGroup.order || []).indexOf(a.id)
|
|
46
|
-
const indexOfBoards = (playGroup.order || []).indexOf(b.id)
|
|
47
|
-
|
|
48
|
-
// 두 아이디의 순서를 비교하여 정렬합니다.
|
|
49
|
-
if (indexOfOrder === -1 && indexOfBoards === -1) {
|
|
50
|
-
// 두 아이디 모두 배열 A에 없는 경우, 그대로 유지합니다.
|
|
51
|
-
return 0
|
|
52
|
-
} else if (indexOfOrder === -1) {
|
|
53
|
-
// 아이디 A만 배열 A에 없는 경우, 아이디 B를 먼저 정렬합니다.
|
|
54
|
-
return 1
|
|
55
|
-
} else if (indexOfBoards === -1) {
|
|
56
|
-
// 아이디 B만 배열 A에 없는 경우, 아이디 A를 먼저 정렬합니다.
|
|
57
|
-
return -1
|
|
58
|
-
} else {
|
|
59
|
-
// 두 아이디 모두 배열 A에 있는 경우, 배열 A의 아이디 순서대로 정렬합니다.
|
|
60
|
-
return indexOfOrder - indexOfBoards
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
} else {
|
|
64
|
-
throw 'parameter id or name mandatory'
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
base: getContextPath(domain?.subdomain) + (domain ? '/' : ''),
|
|
69
|
-
playGroup
|
|
70
|
-
}
|
|
71
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import * as genericPool from 'generic-pool'
|
|
2
|
-
|
|
3
|
-
import { config, logger } from '@things-factory/env'
|
|
4
|
-
|
|
5
|
-
try {
|
|
6
|
-
var puppeteer = require('puppeteer')
|
|
7
|
-
} catch (err) {
|
|
8
|
-
logger.error(err)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
var headlessPool
|
|
12
|
-
|
|
13
|
-
export function getHeadlessPool() {
|
|
14
|
-
if (!headlessPool) {
|
|
15
|
-
headlessPool = genericPool.createPool(
|
|
16
|
-
{
|
|
17
|
-
create() {
|
|
18
|
-
console.log('headless instance in headless-pool-for-board about to create')
|
|
19
|
-
return initializeChromium()
|
|
20
|
-
},
|
|
21
|
-
validate(browser) {
|
|
22
|
-
return Promise.race([
|
|
23
|
-
new Promise(res => setTimeout(() => res(false), 1500)),
|
|
24
|
-
browser
|
|
25
|
-
//@ts-ignore
|
|
26
|
-
.version()
|
|
27
|
-
.then(_ => true)
|
|
28
|
-
.catch(_ => false)
|
|
29
|
-
])
|
|
30
|
-
},
|
|
31
|
-
destroy(browser) {
|
|
32
|
-
//@ts-ignore
|
|
33
|
-
return browser.close()
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
min: 2,
|
|
38
|
-
max: 10,
|
|
39
|
-
testOnBorrow: true,
|
|
40
|
-
acquireTimeoutMillis: 15000
|
|
41
|
-
}
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return headlessPool
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const CHROMIUM_PATH = config.get('CHROMIUM_PATH')
|
|
49
|
-
|
|
50
|
-
async function initializeChromium() {
|
|
51
|
-
try {
|
|
52
|
-
if (!puppeteer) {
|
|
53
|
-
return
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
var launchSetting = {
|
|
57
|
-
args: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],
|
|
58
|
-
headless: 'shell'
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (CHROMIUM_PATH) {
|
|
62
|
-
launchSetting['executablePath'] = CHROMIUM_PATH
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const browser = await puppeteer.launch(launchSetting)
|
|
66
|
-
|
|
67
|
-
return browser
|
|
68
|
-
} catch (err) {
|
|
69
|
-
logger.error(err)
|
|
70
|
-
}
|
|
71
|
-
}
|