@things-factory/dataset 8.0.0-beta.9 → 8.0.2
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/client/activities/activity-data-collect-edit.ts +105 -0
- package/client/activities/activity-data-collect-view.ts +91 -0
- package/client/activities/activity-data-review-edit.ts +278 -0
- package/client/activities/activity-data-review-view.ts +226 -0
- package/client/activities/activity-ooc-resolve-edit.ts +195 -0
- package/client/activities/activity-ooc-resolve-view.ts +143 -0
- package/client/activities/activity-ooc-review-edit.ts +173 -0
- package/client/activities/activity-ooc-review-view.ts +129 -0
- package/client/bootstrap.ts +35 -0
- package/client/components/data-entry-form.ts +109 -0
- package/client/index.ts +1 -0
- package/client/pages/data-archive/data-archive-list-page.ts +277 -0
- package/client/pages/data-archive/data-archive-request-popup.ts +177 -0
- package/client/pages/data-entry/data-entry-list-page.ts +464 -0
- package/client/pages/data-key-set/data-key-item-list.ts +183 -0
- package/client/pages/data-key-set/data-key-set-importer.ts +89 -0
- package/client/pages/data-key-set/data-key-set-list-page.ts +413 -0
- package/client/pages/data-ooc/data-ooc-list-page.ts +549 -0
- package/client/pages/data-ooc/data-ooc-page.ts +164 -0
- package/client/pages/data-ooc/data-ooc-view.ts +236 -0
- package/client/pages/data-ooc/data-oocs-page.ts +200 -0
- package/client/pages/data-report/data-report-embed-page.ts +108 -0
- package/client/pages/data-report/data-report-list-page.ts +454 -0
- package/client/pages/data-report/data-report-samples-page.ts +174 -0
- package/client/pages/data-report/jasper-report-oocs-page.ts +110 -0
- package/client/pages/data-report/jasper-report-samples-crosstab-page.ts +110 -0
- package/client/pages/data-report/jasper-report-samples-page.ts +110 -0
- package/client/pages/data-sample/data-sample-list-page.ts +442 -0
- package/client/pages/data-sample/data-sample-page.ts +55 -0
- package/client/pages/data-sample/data-sample-search-page.ts +424 -0
- package/client/pages/data-sample/data-sample-view.ts +292 -0
- package/client/pages/data-sample/data-samples-page.ts +249 -0
- package/client/pages/data-sensor/data-sensor-list-page.ts +456 -0
- package/client/pages/data-set/data-item-list.ts +304 -0
- package/client/pages/data-set/data-set-importer.ts +89 -0
- package/client/pages/data-set/data-set-list-page.ts +1078 -0
- package/client/pages/data-summary/data-summary-list-page.ts +363 -0
- package/client/pages/data-summary/data-summary-period-page.ts +439 -0
- package/client/pages/data-summary/data-summary-search-page.ts +426 -0
- package/client/pages/data-summary/data-summary-view.ts +133 -0
- package/client/route.ts +91 -0
- package/client/tsconfig.json +13 -0
- package/dist-client/activities/activity-data-review-edit.js +19 -10
- package/dist-client/activities/activity-data-review-edit.js.map +1 -1
- package/dist-client/activities/activity-data-review-view.js +80 -0
- package/dist-client/activities/activity-data-review-view.js.map +1 -1
- package/dist-client/pages/data-entry/data-entry-list-page.js +2 -2
- package/dist-client/pages/data-entry/data-entry-list-page.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controllers/create-data-ooc.js +2 -0
- package/dist-server/controllers/create-data-ooc.js.map +1 -1
- package/dist-server/service/data-archive/index.d.ts +1 -1
- package/dist-server/service/data-ooc/index.d.ts +1 -1
- package/dist-server/service/data-sample/data-sample-query.d.ts +1 -1
- package/dist-server/service/data-sample/data-sample-query.js +3 -3
- package/dist-server/service/data-sample/data-sample-query.js.map +1 -1
- package/dist-server/service/data-sample/index.d.ts +1 -1
- package/dist-server/service/data-set/index.d.ts +1 -1
- package/dist-server/service/index.d.ts +2 -2
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +26 -26
- package/server/activities/activity-data-collect.ts +100 -0
- package/server/activities/activity-data-review.ts +109 -0
- package/server/activities/activity-ooc-resolve.ts +123 -0
- package/server/activities/activity-ooc-review.ts +95 -0
- package/server/activities/index.ts +11 -0
- package/server/controllers/create-data-ooc.ts +80 -0
- package/server/controllers/create-data-sample.ts +323 -0
- package/server/controllers/data-use-case.ts +98 -0
- package/server/controllers/finalize-data-collection.ts +388 -0
- package/server/controllers/index.ts +6 -0
- package/server/controllers/issue-data-collection-task.ts +70 -0
- package/server/controllers/issue-ooc-resolve.ts +58 -0
- package/server/controllers/issue-ooc-review.ts +52 -0
- package/server/controllers/jasper-report.ts +186 -0
- package/server/controllers/query-data-summary-by-period.ts +178 -0
- package/server/controllers/shiny-report.ts +54 -0
- package/server/engine/index.ts +1 -0
- package/server/engine/task/create-data-sample.ts +100 -0
- package/server/engine/task/index.ts +2 -0
- package/server/engine/task/issue-collect-data.ts +45 -0
- package/server/index.ts +8 -0
- package/server/routes.ts +188 -0
- package/server/service/data-archive/data-archive-mutation.ts +273 -0
- package/server/service/data-archive/data-archive-query.ts +58 -0
- package/server/service/data-archive/data-archive-type.ts +48 -0
- package/server/service/data-archive/data-archive.ts +69 -0
- package/server/service/data-archive/index.ts +6 -0
- package/server/service/data-key-set/data-key-item-type.ts +31 -0
- package/server/service/data-key-set/data-key-set-mutation.ts +201 -0
- package/server/service/data-key-set/data-key-set-query.ts +68 -0
- package/server/service/data-key-set/data-key-set-type.ts +70 -0
- package/server/service/data-key-set/data-key-set.ts +86 -0
- package/server/service/data-key-set/index.ts +6 -0
- package/server/service/data-ooc/data-ooc-mutation.ts +154 -0
- package/server/service/data-ooc/data-ooc-query.ts +106 -0
- package/server/service/data-ooc/data-ooc-subscription.ts +48 -0
- package/server/service/data-ooc/data-ooc-type.ts +71 -0
- package/server/service/data-ooc/data-ooc.ts +259 -0
- package/server/service/data-ooc/index.ts +7 -0
- package/server/service/data-sample/data-sample-mutation.ts +18 -0
- package/server/service/data-sample/data-sample-query.ts +215 -0
- package/server/service/data-sample/data-sample-type.ts +47 -0
- package/server/service/data-sample/data-sample.ts +193 -0
- package/server/service/data-sample/index.ts +6 -0
- package/server/service/data-sensor/data-sensor-mutation.ts +116 -0
- package/server/service/data-sensor/data-sensor-query.ts +76 -0
- package/server/service/data-sensor/data-sensor-type.ts +104 -0
- package/server/service/data-sensor/data-sensor.ts +126 -0
- package/server/service/data-sensor/index.ts +6 -0
- package/server/service/data-set/data-item-type.ts +155 -0
- package/server/service/data-set/data-set-mutation.ts +552 -0
- package/server/service/data-set/data-set-query.ts +461 -0
- package/server/service/data-set/data-set-type.ts +204 -0
- package/server/service/data-set/data-set.ts +326 -0
- package/server/service/data-set/index.ts +6 -0
- package/server/service/data-set-history/data-set-history-query.ts +126 -0
- package/server/service/data-set-history/data-set-history-type.ts +12 -0
- package/server/service/data-set-history/data-set-history.ts +217 -0
- package/server/service/data-set-history/event-subscriber.ts +17 -0
- package/server/service/data-set-history/index.ts +7 -0
- package/server/service/data-spec/data-spec-manager.ts +21 -0
- package/server/service/data-spec/data-spec-query.ts +21 -0
- package/server/service/data-spec/data-spec.ts +45 -0
- package/server/service/data-spec/index.ts +5 -0
- package/server/service/data-summary/data-summary-mutation.ts +45 -0
- package/server/service/data-summary/data-summary-query.ts +179 -0
- package/server/service/data-summary/data-summary-type.ts +86 -0
- package/server/service/data-summary/data-summary.ts +170 -0
- package/server/service/data-summary/index.ts +7 -0
- package/server/service/index.ts +57 -0
- package/server/tsconfig.json +10 -0
- package/server/utils/config-resolver.ts +29 -0
- package/server/utils/index.ts +1 -0
package/server/routes.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { In } from 'typeorm'
|
|
2
|
+
|
|
3
|
+
import { Domain, getDataSource } from '@things-factory/shell'
|
|
4
|
+
import { User } from '@things-factory/auth-base'
|
|
5
|
+
import { runScenario } from '@things-factory/integration-base'
|
|
6
|
+
import { ScheduleRegisterRequest } from '@things-factory/scheduler-client'
|
|
7
|
+
|
|
8
|
+
import { createDataSample } from './controllers/create-data-sample'
|
|
9
|
+
import { renderJasperReport } from './controllers/jasper-report'
|
|
10
|
+
import { renderShinyReport } from './controllers/shiny-report'
|
|
11
|
+
import { issueDataCollectionTask } from './controllers/issue-data-collection-task'
|
|
12
|
+
import { DataSensor } from './service/data-sensor/data-sensor'
|
|
13
|
+
import { DataSet } from './service/data-set/data-set'
|
|
14
|
+
|
|
15
|
+
process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
|
|
16
|
+
/*
|
|
17
|
+
* can add global public routes to application (auth not required, tenancy not required)
|
|
18
|
+
*
|
|
19
|
+
* ex) routes.get('/path', async(context, next) => {})
|
|
20
|
+
* ex) routes.post('/path', async(context, next) => {})
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
globalPublicRouter.post('/sensor-data', async (context, next) => {
|
|
24
|
+
// 데이타 검증
|
|
25
|
+
const { deviceId, data, rawData, timestamp = Date.now() } = context.request.body
|
|
26
|
+
if (!deviceId) {
|
|
27
|
+
throw new Error(`The deviceId(${deviceId}) property are mandatory`)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// make new data-sample
|
|
31
|
+
await getDataSource().transaction(async tx => {
|
|
32
|
+
// find sensor through deviceId
|
|
33
|
+
const sensor = await tx.getRepository(DataSensor).findOne({
|
|
34
|
+
where: { deviceId },
|
|
35
|
+
relations: ['domain', 'appliance', 'dataSet', 'decoder']
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if (!sensor) {
|
|
39
|
+
throw new Error(`Sensor having given deviceId(${deviceId}) not found`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!sensor.active) {
|
|
43
|
+
throw new Error(`State of the sensor given deviceId(${deviceId}) is not active`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!sensor.appliance) {
|
|
47
|
+
throw new Error(`Appliance of the sensor given deviceId(${deviceId}) is not set up`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const domain = sensor.domain
|
|
51
|
+
const dataSet = sensor.dataSet
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
원칙적으로 user 인증정보를 가지고 요청해야 하지만, 인증정보를 보낼 수 없는 상황이라고 전제하여 처리한다.
|
|
55
|
+
앞으로, 보완되어야 한다.
|
|
56
|
+
*/
|
|
57
|
+
const user: User =
|
|
58
|
+
context.user ||
|
|
59
|
+
(await tx.getRepository(User).findOne({
|
|
60
|
+
where: {
|
|
61
|
+
reference: sensor.appliance.id,
|
|
62
|
+
userType: 'appliance'
|
|
63
|
+
}
|
|
64
|
+
}))
|
|
65
|
+
|
|
66
|
+
context.state = {
|
|
67
|
+
user,
|
|
68
|
+
...context.state,
|
|
69
|
+
domain,
|
|
70
|
+
tx
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
var decoded
|
|
74
|
+
if (sensor.decoder) {
|
|
75
|
+
const { name: scenarioName } = sensor.decoder
|
|
76
|
+
const variables = {
|
|
77
|
+
dataSensor: sensor,
|
|
78
|
+
source: deviceId,
|
|
79
|
+
data,
|
|
80
|
+
rawData,
|
|
81
|
+
timestamp
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
decoded = (await runScenario(null, scenarioName, variables, context))?.result
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (dataSet) {
|
|
88
|
+
await createDataSample(
|
|
89
|
+
{
|
|
90
|
+
dataSet,
|
|
91
|
+
data,
|
|
92
|
+
rawData,
|
|
93
|
+
source: deviceId,
|
|
94
|
+
collectedAt: new Date(timestamp),
|
|
95
|
+
...decoded
|
|
96
|
+
},
|
|
97
|
+
context
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
context.status = 200
|
|
102
|
+
context.body = {
|
|
103
|
+
data,
|
|
104
|
+
...decoded
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
/* When a callback occurs from the scheduler when a scheduled dataset is on schedule, data collection task for the dataset should be issued. */
|
|
110
|
+
globalPublicRouter.post('/callback-schedule-for-dataset', async (context, next) => {
|
|
111
|
+
const { client } = context.request.body as ScheduleRegisterRequest
|
|
112
|
+
|
|
113
|
+
if (!client || typeof client !== 'object') {
|
|
114
|
+
throw new Error('client property should be a part of callback body.')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const { group: domainId, key: dataSetId } = client
|
|
118
|
+
|
|
119
|
+
if (!domainId || !dataSetId) {
|
|
120
|
+
throw new Error(`group(${domainId}) and key(${dataSetId}) properties should not be empty`)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await issueDataCollectionTask(domainId, dataSetId, context)
|
|
124
|
+
|
|
125
|
+
context.status = 200
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
/* When a callback occurs from the scheduler when a scheduled summary is on schedule, data summary procedure for the dataset should be executed. */
|
|
129
|
+
globalPublicRouter.post('/callback-schedule-for-data-summary', async (context, next) => {
|
|
130
|
+
const { client } = context.request.body as ScheduleRegisterRequest
|
|
131
|
+
|
|
132
|
+
if (!client || typeof client !== 'object') {
|
|
133
|
+
throw new Error('client property should be a part of callback body.')
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const { group: domainId, key: dataSetId } = client
|
|
137
|
+
|
|
138
|
+
if (!domainId || !dataSetId) {
|
|
139
|
+
throw new Error(`group(${domainId}) and key(${dataSetId}) properties should not be empty`)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await getDataSource().transaction(async tx => {
|
|
143
|
+
const domain = await tx.getRepository(Domain).findOneBy({ id: domainId })
|
|
144
|
+
|
|
145
|
+
if (!domain) {
|
|
146
|
+
throw new Error(`domain(${domainId}) not found`)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const dataSet = await tx
|
|
150
|
+
.getRepository(DataSet)
|
|
151
|
+
.findOne({ where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id: dataSetId } })
|
|
152
|
+
|
|
153
|
+
// do what you gotta do
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
context.status = 200
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
|
|
161
|
+
/*
|
|
162
|
+
* can add global private routes to application (auth required, tenancy not required)
|
|
163
|
+
*/
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
process.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {
|
|
167
|
+
/*
|
|
168
|
+
* can add domain public routes to application (auth not required, tenancy required)
|
|
169
|
+
*/
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {
|
|
173
|
+
/*
|
|
174
|
+
* can add domain private routes to application (auth required, tenancy required)
|
|
175
|
+
*/
|
|
176
|
+
domainPrivateRouter.get('/data-report/jasper', async (context, next) => {
|
|
177
|
+
context.body = await renderJasperReport(context)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
domainPrivateRouter.get('/data-report/shiny', async (context, next) => {
|
|
181
|
+
await renderShinyReport(context)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
domainPrivateRouter.get('/data-report/:reportType', async (context, next) => {
|
|
185
|
+
let { reportType } = context.params
|
|
186
|
+
context.body = `${reportType} Not Implemented.`
|
|
187
|
+
})
|
|
188
|
+
})
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import i18next from 'i18next'
|
|
2
|
+
import fetch from 'node-fetch'
|
|
3
|
+
import { Arg, Ctx, Directive, Mutation, Resolver } from 'type-graphql'
|
|
4
|
+
import { In } from 'typeorm'
|
|
5
|
+
|
|
6
|
+
import { getEndpointUrl } from '../../utils/config-resolver'
|
|
7
|
+
import { DataArchive } from './data-archive'
|
|
8
|
+
import { DataArchivePatch, NewDataArchive } from './data-archive-type'
|
|
9
|
+
|
|
10
|
+
const { config } = require('@things-factory/env')
|
|
11
|
+
const crypto = require('crypto')
|
|
12
|
+
|
|
13
|
+
@Resolver(DataArchive)
|
|
14
|
+
export class DataArchiveMutation {
|
|
15
|
+
/**
|
|
16
|
+
* It may use 'func-[dev]-data-set-download' in https://github.com/operatochef/serverless
|
|
17
|
+
* This function requests athena query and save the result as csv.gz in s3
|
|
18
|
+
*/
|
|
19
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
20
|
+
@Directive('@transaction')
|
|
21
|
+
@Mutation(returns => DataArchive, { description: 'To create new DataArchive' })
|
|
22
|
+
async generatePresignedUrl(
|
|
23
|
+
@Arg('patch') patch: DataArchivePatch,
|
|
24
|
+
@Ctx() context: ResolverContext
|
|
25
|
+
): Promise<DataArchive> {
|
|
26
|
+
const { domain, user, tx, notify, lng } = context.state
|
|
27
|
+
// const dataArchiveRepo = tx.getRepository(DataArchive)
|
|
28
|
+
const t = i18next.getFixedT(lng, 'translations')
|
|
29
|
+
const {
|
|
30
|
+
dataset: {
|
|
31
|
+
endpoint,
|
|
32
|
+
datasource: { database }
|
|
33
|
+
}
|
|
34
|
+
} = config.get('dataArchive')
|
|
35
|
+
|
|
36
|
+
const body = JSON.stringify({
|
|
37
|
+
domain: domain?.subdomain,
|
|
38
|
+
database,
|
|
39
|
+
...patch?.requestParams
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const url = getEndpointUrl(endpoint)
|
|
43
|
+
|
|
44
|
+
const fetched = await fetch(`${url}`, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
body
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const message = {
|
|
51
|
+
receivers: [user.email],
|
|
52
|
+
mode: 'in-app',
|
|
53
|
+
title: '',
|
|
54
|
+
body: '',
|
|
55
|
+
url: ''
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (fetched.ok) {
|
|
59
|
+
const response = await fetched.json()
|
|
60
|
+
patch.downloadUrl = response['presignedUrl']
|
|
61
|
+
patch.status = 'done'
|
|
62
|
+
|
|
63
|
+
message['title'] = t('title.data-archive downloads ready')
|
|
64
|
+
message['url'] = patch.downloadUrl
|
|
65
|
+
} else {
|
|
66
|
+
const error = await fetched.text()
|
|
67
|
+
console.log(error)
|
|
68
|
+
patch.status = 'error'
|
|
69
|
+
|
|
70
|
+
message['title'] = t('title.data-archive request failed')
|
|
71
|
+
// may not user-friendly message
|
|
72
|
+
message['body'] = error
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const result = await this.updateDataArchive(patch.id, patch, context)
|
|
76
|
+
|
|
77
|
+
notify && notify(message)
|
|
78
|
+
|
|
79
|
+
return result
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
83
|
+
@Directive('@transaction')
|
|
84
|
+
@Mutation(returns => DataArchive, { description: 'To create new DataArchive' })
|
|
85
|
+
async createDataArchive(
|
|
86
|
+
@Arg('dataArchive') dataArchive: NewDataArchive,
|
|
87
|
+
@Ctx() context: ResolverContext
|
|
88
|
+
): Promise<DataArchive> {
|
|
89
|
+
const { domain, user, tx } = context.state
|
|
90
|
+
const dataArchiveRepo = tx.getRepository(DataArchive)
|
|
91
|
+
|
|
92
|
+
const result = await dataArchiveRepo.save({
|
|
93
|
+
...dataArchive,
|
|
94
|
+
domain,
|
|
95
|
+
creator: user,
|
|
96
|
+
updater: user
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
return result
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
103
|
+
@Directive('@transaction')
|
|
104
|
+
@Mutation(returns => DataArchive, { description: 'To modify DataArchive information' })
|
|
105
|
+
async updateDataArchive(
|
|
106
|
+
@Arg('id') id: string,
|
|
107
|
+
@Arg('patch') patch: DataArchivePatch,
|
|
108
|
+
@Ctx() context: ResolverContext
|
|
109
|
+
): Promise<DataArchive> {
|
|
110
|
+
const { domain, user, tx } = context.state
|
|
111
|
+
const dataArchiveRepo = tx.getRepository(DataArchive)
|
|
112
|
+
|
|
113
|
+
const dataArchive = await dataArchiveRepo.findOne({
|
|
114
|
+
where: { domain: { id: domain.id }, id },
|
|
115
|
+
relations: ['domain', 'creator', 'updater']
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
const result = await dataArchiveRepo.save({
|
|
119
|
+
...dataArchive,
|
|
120
|
+
...patch,
|
|
121
|
+
updater: user
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
return result
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
128
|
+
@Directive('@transaction')
|
|
129
|
+
@Mutation(returns => [DataArchive], { description: "To modify multiple DataArchives' information" })
|
|
130
|
+
async updateMultipleDataArchive(
|
|
131
|
+
@Arg('patches', type => [DataArchivePatch]) patches: DataArchivePatch[],
|
|
132
|
+
@Ctx() context: any
|
|
133
|
+
): Promise<DataArchive[]> {
|
|
134
|
+
const { domain, user, tx } = context.state
|
|
135
|
+
const dataArchiveRepo = tx.getRepository(DataArchive)
|
|
136
|
+
|
|
137
|
+
let results = []
|
|
138
|
+
const _createRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === '+')
|
|
139
|
+
const _updateRecords = patches.filter((patch: any) => patch.cuFlag.toUpperCase() === 'M')
|
|
140
|
+
|
|
141
|
+
if (_createRecords.length > 0) {
|
|
142
|
+
const cuFlag = '+'
|
|
143
|
+
for (let i = 0; i < _createRecords.length; i++) {
|
|
144
|
+
const newRecord = _createRecords[i]
|
|
145
|
+
|
|
146
|
+
const result = await dataArchiveRepo.save({
|
|
147
|
+
...newRecord,
|
|
148
|
+
domain,
|
|
149
|
+
creator: user,
|
|
150
|
+
updater: user
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
results.push({
|
|
154
|
+
...result,
|
|
155
|
+
cuFlag
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (_updateRecords.length > 0) {
|
|
161
|
+
const cuFlag = 'M'
|
|
162
|
+
for (let i = 0; i < _updateRecords.length; i++) {
|
|
163
|
+
const newRecord = _updateRecords[i]
|
|
164
|
+
const dataArchive = await dataArchiveRepo.findOne(newRecord.id, {
|
|
165
|
+
relations: ['domain', 'creator', 'updater']
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
const result = await dataArchiveRepo.save({
|
|
169
|
+
...dataArchive,
|
|
170
|
+
...newRecord,
|
|
171
|
+
updater: user
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
results.push({
|
|
175
|
+
...result,
|
|
176
|
+
cuFlag
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return results
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
185
|
+
@Directive('@transaction')
|
|
186
|
+
@Mutation(returns => Boolean, { description: 'To delete DataArchive' })
|
|
187
|
+
async deleteDataArchive(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
188
|
+
const { domain, tx } = context.state
|
|
189
|
+
|
|
190
|
+
await tx.getRepository(DataArchive).delete({ domain: { id: domain.id }, id })
|
|
191
|
+
return true
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
195
|
+
@Directive('@transaction')
|
|
196
|
+
@Mutation(returns => Boolean, { description: 'To delete multiple dataArchives' })
|
|
197
|
+
async deleteDataArchives(
|
|
198
|
+
@Arg('ids', type => [String]) ids: string[],
|
|
199
|
+
@Ctx() context: ResolverContext
|
|
200
|
+
): Promise<boolean> {
|
|
201
|
+
const { domain, tx } = context.state
|
|
202
|
+
|
|
203
|
+
await tx.getRepository(DataArchive).delete({
|
|
204
|
+
domain: { id: domain.id },
|
|
205
|
+
id: In(ids)
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
return true
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
212
|
+
@Directive('@transaction')
|
|
213
|
+
@Mutation(returns => Boolean, { description: 'To import multiple data-archives' })
|
|
214
|
+
async importDataArchives(
|
|
215
|
+
@Arg('dataArchives', type => [DataArchivePatch]) dataArchives: DataArchive[],
|
|
216
|
+
@Ctx() context: ResolverContext
|
|
217
|
+
): Promise<boolean> {
|
|
218
|
+
const { domain, tx } = context.state
|
|
219
|
+
const dataArchiveRepo = tx.getRepository(DataArchive)
|
|
220
|
+
|
|
221
|
+
await Promise.all(
|
|
222
|
+
dataArchives.map(async (dataArchive: DataArchive) => {
|
|
223
|
+
const createdDataArchive: DataArchive = await dataArchiveRepo.save({
|
|
224
|
+
domain,
|
|
225
|
+
...dataArchive
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
return true
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@Directive('@privilege(category: "data-archive", privilege: "mutation", domainOwnerGranted: true)')
|
|
234
|
+
@Directive('@transaction')
|
|
235
|
+
@Mutation(returns => [DataArchive], { description: 'To copy multiple data-archives' })
|
|
236
|
+
async copyDataArchives(
|
|
237
|
+
@Arg('ids', type => [String]) ids: string[],
|
|
238
|
+
@Ctx() context: ResolverContext
|
|
239
|
+
): Promise<DataArchive[]> {
|
|
240
|
+
const { domain, user, tx } = context.state
|
|
241
|
+
const dataArchiveRepo = tx.getRepository(DataArchive)
|
|
242
|
+
|
|
243
|
+
const originals = await dataArchiveRepo.find({
|
|
244
|
+
where: {
|
|
245
|
+
id: In(ids),
|
|
246
|
+
domain: { id: domain.id }
|
|
247
|
+
},
|
|
248
|
+
relations: ['domain']
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
if (originals.length == 0) {
|
|
252
|
+
return []
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
var newCopys = originals.map(dataArchive => {
|
|
256
|
+
let dataArchiveId = crypto.randomUUID()
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
...dataArchive,
|
|
260
|
+
id: dataArchiveId,
|
|
261
|
+
domain,
|
|
262
|
+
creator: user,
|
|
263
|
+
updater: user,
|
|
264
|
+
updatedAt: undefined,
|
|
265
|
+
createdAt: undefined
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
var copiedDataArchives = await dataArchiveRepo.save(newCopys)
|
|
270
|
+
|
|
271
|
+
return copiedDataArchives
|
|
272
|
+
}
|
|
273
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Arg, Args, Ctx, Directive, FieldResolver, Query, Resolver, Root } from 'type-graphql'
|
|
2
|
+
|
|
3
|
+
import { Role, User } from '@things-factory/auth-base'
|
|
4
|
+
import { Domain, getQueryBuilderFromListParams, ListParam, getRepository } from '@things-factory/shell'
|
|
5
|
+
|
|
6
|
+
import { DataArchive } from './data-archive'
|
|
7
|
+
import { DataArchiveList } from './data-archive-type'
|
|
8
|
+
|
|
9
|
+
var parser = require('cron-parser')
|
|
10
|
+
|
|
11
|
+
@Resolver(DataArchive)
|
|
12
|
+
export class DataArchiveQuery {
|
|
13
|
+
@Directive('@privilege(category: "data-archive", privilege: "query", domainOwnerGranted: true)')
|
|
14
|
+
@Query(returns => DataArchive, { description: 'To fetch a DataArchive' })
|
|
15
|
+
async dataArchive(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<DataArchive> {
|
|
16
|
+
const { domain } = context.state
|
|
17
|
+
|
|
18
|
+
return await getRepository(DataArchive).findOne({
|
|
19
|
+
where: { domain: { id: domain.id }, id }
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Directive('@privilege(category: "data-archive", privilege: "query", domainOwnerGranted: true)')
|
|
24
|
+
@Query(returns => DataArchiveList, { description: 'To fetch multiple DataArchives' })
|
|
25
|
+
async dataArchives(
|
|
26
|
+
@Args(type => ListParam) params: ListParam,
|
|
27
|
+
@Ctx() context: ResolverContext
|
|
28
|
+
): Promise<DataArchiveList> {
|
|
29
|
+
const { domain } = context.state
|
|
30
|
+
|
|
31
|
+
const queryBuilder = getQueryBuilderFromListParams({
|
|
32
|
+
repository: getRepository(DataArchive),
|
|
33
|
+
params,
|
|
34
|
+
domain,
|
|
35
|
+
alias: 'dataArchive',
|
|
36
|
+
searchables: []
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const [items, total] = await queryBuilder.getManyAndCount()
|
|
40
|
+
|
|
41
|
+
return { items, total }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@FieldResolver(type => Domain)
|
|
45
|
+
async domain(@Root() dataArchive: DataArchive): Promise<Domain> {
|
|
46
|
+
return dataArchive.domainId && (await getRepository(Domain).findOneBy({ id: dataArchive.domainId }))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@FieldResolver(type => User)
|
|
50
|
+
async updater(@Root() dataArchive: DataArchive): Promise<User> {
|
|
51
|
+
return dataArchive.updaterId && (await getRepository(User).findOneBy({ id: dataArchive.updaterId }))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@FieldResolver(type => User)
|
|
55
|
+
async creator(@Root() dataArchive: DataArchive): Promise<User> {
|
|
56
|
+
return dataArchive.creatorId && (await getRepository(User).findOneBy({ id: dataArchive.creatorId }))
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Field, ID, InputType, Int, ObjectType } from 'type-graphql'
|
|
2
|
+
import { DataArchive } from './data-archive'
|
|
3
|
+
import { ScalarObject } from '@things-factory/shell'
|
|
4
|
+
|
|
5
|
+
@InputType()
|
|
6
|
+
export class NewDataArchive {
|
|
7
|
+
@Field({ nullable: true })
|
|
8
|
+
type?: 'manual' | 'automatic' | string
|
|
9
|
+
|
|
10
|
+
@Field(type => ScalarObject, { nullable: true })
|
|
11
|
+
requestParams?: { [key: string]: any }
|
|
12
|
+
|
|
13
|
+
@Field({ nullable: true })
|
|
14
|
+
downloadUrl?: string
|
|
15
|
+
|
|
16
|
+
@Field({ nullable: true })
|
|
17
|
+
status?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@InputType()
|
|
21
|
+
export class DataArchivePatch {
|
|
22
|
+
@Field(type => ID, { nullable: true })
|
|
23
|
+
id?: string
|
|
24
|
+
|
|
25
|
+
@Field({ nullable: true })
|
|
26
|
+
type?: 'manual' | 'automatic' | string
|
|
27
|
+
|
|
28
|
+
@Field(type => ScalarObject, { nullable: true })
|
|
29
|
+
requestParams?: { [key: string]: any }
|
|
30
|
+
|
|
31
|
+
@Field({ nullable: true })
|
|
32
|
+
downloadUrl?: string
|
|
33
|
+
|
|
34
|
+
@Field({ nullable: true })
|
|
35
|
+
status?: string
|
|
36
|
+
|
|
37
|
+
@Field({ nullable: true })
|
|
38
|
+
cuFlag: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@ObjectType()
|
|
42
|
+
export class DataArchiveList {
|
|
43
|
+
@Field(type => [DataArchive])
|
|
44
|
+
items: DataArchive[]
|
|
45
|
+
|
|
46
|
+
@Field(type => Int)
|
|
47
|
+
total: number
|
|
48
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Field, ID, ObjectType, registerEnumType } from 'type-graphql'
|
|
2
|
+
import {
|
|
3
|
+
Column,
|
|
4
|
+
CreateDateColumn,
|
|
5
|
+
Entity,
|
|
6
|
+
Index,
|
|
7
|
+
ManyToOne,
|
|
8
|
+
PrimaryGeneratedColumn,
|
|
9
|
+
RelationId,
|
|
10
|
+
UpdateDateColumn,
|
|
11
|
+
VersionColumn
|
|
12
|
+
} from 'typeorm'
|
|
13
|
+
|
|
14
|
+
import { Role, User } from '@things-factory/auth-base'
|
|
15
|
+
import { Domain, ScalarObject } from '@things-factory/shell'
|
|
16
|
+
|
|
17
|
+
@Entity()
|
|
18
|
+
@Index('ix_data_archive_0', (dataArchive: DataArchive) => [dataArchive.id], { unique: true })
|
|
19
|
+
@ObjectType({ description: 'Entity for DataArchive' })
|
|
20
|
+
export class DataArchive {
|
|
21
|
+
@PrimaryGeneratedColumn('uuid')
|
|
22
|
+
@Field(type => ID)
|
|
23
|
+
readonly id: string
|
|
24
|
+
|
|
25
|
+
@ManyToOne(type => Domain)
|
|
26
|
+
@Field(type => Domain)
|
|
27
|
+
domain?: Domain
|
|
28
|
+
|
|
29
|
+
@RelationId((dataArchive: DataArchive) => dataArchive.domain)
|
|
30
|
+
domainId?: string
|
|
31
|
+
|
|
32
|
+
@Column({ nullable: true })
|
|
33
|
+
@Field({ nullable: true })
|
|
34
|
+
type?: 'manual' | 'automatic' | string
|
|
35
|
+
|
|
36
|
+
@Column('simple-json', { nullable: true })
|
|
37
|
+
@Field(type => ScalarObject, { nullable: true })
|
|
38
|
+
requestParams?: { [key: string]: any }
|
|
39
|
+
|
|
40
|
+
@Column({ nullable: true })
|
|
41
|
+
@Field({ nullable: true })
|
|
42
|
+
downloadUrl?: string
|
|
43
|
+
|
|
44
|
+
@Column({ nullable: true })
|
|
45
|
+
@Field({ nullable: true })
|
|
46
|
+
status?: string
|
|
47
|
+
|
|
48
|
+
@CreateDateColumn()
|
|
49
|
+
@Field({ nullable: true })
|
|
50
|
+
createdAt?: Date
|
|
51
|
+
|
|
52
|
+
@UpdateDateColumn()
|
|
53
|
+
@Field({ nullable: true })
|
|
54
|
+
updatedAt?: Date
|
|
55
|
+
|
|
56
|
+
@ManyToOne(type => User, { nullable: true })
|
|
57
|
+
@Field(type => User, { nullable: true })
|
|
58
|
+
creator?: User
|
|
59
|
+
|
|
60
|
+
@RelationId((dataArchive: DataArchive) => dataArchive.creator)
|
|
61
|
+
creatorId?: string
|
|
62
|
+
|
|
63
|
+
@ManyToOne(type => User, { nullable: true })
|
|
64
|
+
@Field(type => User, { nullable: true })
|
|
65
|
+
updater?: User
|
|
66
|
+
|
|
67
|
+
@RelationId((dataArchive: DataArchive) => dataArchive.updater)
|
|
68
|
+
updaterId?: string
|
|
69
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DataArchive } from './data-archive'
|
|
2
|
+
import { DataArchiveMutation } from './data-archive-mutation'
|
|
3
|
+
import { DataArchiveQuery } from './data-archive-query'
|
|
4
|
+
|
|
5
|
+
export const entities = [DataArchive]
|
|
6
|
+
export const resolvers = [DataArchiveQuery, DataArchiveMutation]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Field, InputType, ObjectType } from 'type-graphql'
|
|
2
|
+
|
|
3
|
+
@ObjectType({ description: 'Entity for DataKeyItem' })
|
|
4
|
+
export class DataKeyItem {
|
|
5
|
+
@Field()
|
|
6
|
+
name: string
|
|
7
|
+
|
|
8
|
+
@Field({ nullable: true })
|
|
9
|
+
description?: string
|
|
10
|
+
|
|
11
|
+
@Field({ nullable: true })
|
|
12
|
+
dataKey: string
|
|
13
|
+
|
|
14
|
+
@Field({ nullable: true })
|
|
15
|
+
tKey?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@InputType()
|
|
19
|
+
export class DataKeyItemPatch {
|
|
20
|
+
@Field({ nullable: true })
|
|
21
|
+
name?: string
|
|
22
|
+
|
|
23
|
+
@Field({ nullable: true })
|
|
24
|
+
description?: string
|
|
25
|
+
|
|
26
|
+
@Field({ nullable: true })
|
|
27
|
+
dataKey?: string
|
|
28
|
+
|
|
29
|
+
@Field({ nullable: true })
|
|
30
|
+
tKey?: string
|
|
31
|
+
}
|