@agung_dhewe/webapps 1.1.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.
Files changed (130) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +2 -0
  3. package/jsconfig.json +10 -0
  4. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.css +2 -0
  5. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js +11 -0
  6. package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js.map +1 -0
  7. package/libs/fgta5js-dist/fonts/karla-italic-latin-ext.woff2 +0 -0
  8. package/libs/fgta5js-dist/fonts/karla-italic-latin.woff2 +0 -0
  9. package/libs/fgta5js-dist/fonts/karla-normal-latin-ext.woff2 +0 -0
  10. package/libs/fgta5js-dist/fonts/karla-normal-latin.woff2 +0 -0
  11. package/libs/fgta5js-dist/fonts/karla.css +142 -0
  12. package/libs/webmodule/module-edit.css +163 -0
  13. package/libs/webmodule/module-footer.css +22 -0
  14. package/libs/webmodule/module-list.css +25 -0
  15. package/libs/webmodule/module.css +52 -0
  16. package/libs/webmodule/module.js +195 -0
  17. package/libs/webmodule/pagehelper.mjs +45 -0
  18. package/modules/generator/appgen-components.mjs +142 -0
  19. package/modules/generator/appgen-icons.mjs +6 -0
  20. package/modules/generator/appgen-io.mjs +784 -0
  21. package/modules/generator/appgen-ui-search.mjs +173 -0
  22. package/modules/generator/appgen-ui-unique.mjs +153 -0
  23. package/modules/generator/appgen-ui.mjs +1181 -0
  24. package/modules/generator/generator-context.mjs +18 -0
  25. package/modules/generator/generator-designtemplate.html +1508 -0
  26. package/modules/generator/generator-ext.html +0 -0
  27. package/modules/generator/generator-ext.mjs +3 -0
  28. package/modules/generator/generator.css +642 -0
  29. package/modules/generator/generator.mjs +195 -0
  30. package/modules/generator/generator.png +0 -0
  31. package/modules/generator/generatorEdit.html +185 -0
  32. package/modules/generator/generatorEdit.mjs +238 -0
  33. package/modules/generator/generatorList.html +32 -0
  34. package/modules/generator/generatorList.mjs +243 -0
  35. package/modules/login/login.css +11 -0
  36. package/modules/login/login.html +12 -0
  37. package/modules/login/login.mjs +111 -0
  38. package/package.json +46 -0
  39. package/percobaan/simmpan-ke-minio.js +24 -0
  40. package/src/api.js +80 -0
  41. package/src/apis/generator.api.js +226 -0
  42. package/src/apis/login.api.js +109 -0
  43. package/src/bucket.js +24 -0
  44. package/src/context.js +26 -0
  45. package/src/datalog.sql +22 -0
  46. package/src/datarecords.js +0 -0
  47. package/src/db.js +61 -0
  48. package/src/generator/createApiExtenderModule.js +54 -0
  49. package/src/generator/createApiModule.js +218 -0
  50. package/src/generator/createIcon.js +62 -0
  51. package/src/generator/createInfoAboutExtender.js +42 -0
  52. package/src/generator/createInfoLogs.js +41 -0
  53. package/src/generator/createInfoRecordExtender.js +41 -0
  54. package/src/generator/createModuleContext.js +48 -0
  55. package/src/generator/createModuleDetilEditHtml.js +110 -0
  56. package/src/generator/createModuleDetilEditMjs.js +172 -0
  57. package/src/generator/createModuleDetilListHtml.js +146 -0
  58. package/src/generator/createModuleDetilListMjs.js +73 -0
  59. package/src/generator/createModuleEjs.js +51 -0
  60. package/src/generator/createModuleExtenderHtml.js +43 -0
  61. package/src/generator/createModuleExtenderMjs.js +43 -0
  62. package/src/generator/createModuleHeaderEditHtml.js +148 -0
  63. package/src/generator/createModuleHeaderEditMjs.js +197 -0
  64. package/src/generator/createModuleHeaderListHtml.js +144 -0
  65. package/src/generator/createModuleHeaderListMjs.js +67 -0
  66. package/src/generator/createModuleMjs.js +67 -0
  67. package/src/generator/createModuleRollup.js +42 -0
  68. package/src/generator/createProgramData.js +96 -0
  69. package/src/generator/createTable.js +156 -0
  70. package/src/generator/ddl.js +475 -0
  71. package/src/generator/helper.js +149 -0
  72. package/src/generator/templates/__rollup-module.ejs +90 -0
  73. package/src/generator/templates/api-extender-module.js.ejs +0 -0
  74. package/src/generator/templates/api-module.js.ejs +818 -0
  75. package/src/generator/templates/module-context.ejs +16 -0
  76. package/src/generator/templates/module-ext-about.ejs +1 -0
  77. package/src/generator/templates/module-ext-record.ejs +1 -0
  78. package/src/generator/templates/module-ext.html.ejs +3 -0
  79. package/src/generator/templates/module-ext.mjs.ejs +21 -0
  80. package/src/generator/templates/module-logs.ejs +14 -0
  81. package/src/generator/templates/module.ejs.ejs +48 -0
  82. package/src/generator/templates/module.mjs.ejs +256 -0
  83. package/src/generator/templates/moduleDetilEdit.html.ejs +34 -0
  84. package/src/generator/templates/moduleDetilEdit.mjs.ejs +792 -0
  85. package/src/generator/templates/moduleDetilList.html.ejs +26 -0
  86. package/src/generator/templates/moduleDetilList.mjs.ejs +319 -0
  87. package/src/generator/templates/moduleHeaderEdit.html.ejs +53 -0
  88. package/src/generator/templates/moduleHeaderEdit.mjs.ejs +807 -0
  89. package/src/generator/templates/moduleHeaderList.html.ejs +24 -0
  90. package/src/generator/templates/moduleHeaderList.mjs.ejs +308 -0
  91. package/src/generator/templates/sqlAddField.ejs +3 -0
  92. package/src/generator/templates/sqlAddForeignKey.ejs +12 -0
  93. package/src/generator/templates/sqlAddUniqueIndex.ejs +4 -0
  94. package/src/generator/templates/sqlCreateTable.ejs +9 -0
  95. package/src/generator/templates/sqlDropForeignKey.ejs +3 -0
  96. package/src/generator/templates/sqlDropUniqueIndex.ejs +4 -0
  97. package/src/generator/templates/sqlModifyField.ejs +6 -0
  98. package/src/generator/trygenerate.js +83 -0
  99. package/src/generator/worker.js +389 -0
  100. package/src/helper.js +82 -0
  101. package/src/logger.js +39 -0
  102. package/src/router.js +84 -0
  103. package/src/routers/defaultLoginApi.js +29 -0
  104. package/src/routers/defaultLoginAsset.js +18 -0
  105. package/src/routers/defaultLoginPage.js +36 -0
  106. package/src/routers/defaultRootIndex.js +16 -0
  107. package/src/routers/downloadHandler.js +51 -0
  108. package/src/routers/fileUploadApi.js +15 -0
  109. package/src/routers/generatorApi.js +30 -0
  110. package/src/routers/generatorAsset.js +18 -0
  111. package/src/routers/generatorPage.js +37 -0
  112. package/src/routers/handleError.js +43 -0
  113. package/src/routers/handleModuleNotfound.js +12 -0
  114. package/src/routers/moduleApi.js +34 -0
  115. package/src/routers/modulePage.js +102 -0
  116. package/src/sequencerdoc.js +311 -0
  117. package/src/sequencerline.js +214 -0
  118. package/src/session.js +57 -0
  119. package/src/startup.js +59 -0
  120. package/src/webapps.js +239 -0
  121. package/src/workermanager.js +83 -0
  122. package/templates/_lib_debug.ejs +11 -0
  123. package/templates/_lib_production.ejs +5 -0
  124. package/templates/application.page.ejs +143 -0
  125. package/templates/generator.page.ejs +131 -0
  126. package/templates/index.page.ejs +24 -0
  127. package/templates/login.page.ejs +102 -0
  128. package/templates/moduleError.ejs +16 -0
  129. package/templates/moduleNotfound.ejs +14 -0
  130. package/webapps.code-workspace +11 -0
@@ -0,0 +1,243 @@
1
+ import Context from './generator-context.mjs'
2
+ import * as Extender from './generator-ext.mjs'
3
+
4
+
5
+ const Crsl = Context.Crsl
6
+ const CurrentSectionId = Context.Sections.generatorList
7
+ const CurrentSection = Crsl.Items[CurrentSectionId]
8
+ const CurrentState = {}
9
+
10
+ const tbl = new $fgta5.Gridview('generatorList-tbl')
11
+ const pnl_search = document.getElementById('generatorList-pnl_search')
12
+ const btn_gridload = new $fgta5.ActionButton('generatorList-btn_gridload')
13
+
14
+ export const Section = CurrentSection
15
+ export const SearchParams = {}
16
+
17
+ export async function init(self, args) {
18
+ console.log('initializing generatorList ...')
19
+
20
+ // add event listener
21
+ tbl.addEventListener('nextdata', async evt=>{ tbl_nextdata(self, evt) })
22
+ tbl.addEventListener('sorting', async evt=>{ tbl_sorting(self, evt) })
23
+ tbl.addEventListener('cellclick', async evt=>{ tbl_cellclick(self, evt) })
24
+ tbl.addEventListener('celldblclick', async evt=>{ tbl_celldblclick(self, evt) })
25
+
26
+ btn_gridload.addEventListener('click', async evt=>{ btn_gridload_click(self, evt) })
27
+
28
+
29
+ try {
30
+ // extract custom search panel from template
31
+ const tplSearchPanel = document.querySelector('template[name="custom-search-panel"]')
32
+ if (tplSearchPanel!=null) {
33
+ const clone = tplSearchPanel.content.cloneNode(true); // salin isi template
34
+ pnl_search.prepend(clone)
35
+ }
36
+
37
+ // setup search panel
38
+ const cmps = pnl_search.querySelectorAll('[fgta5-component][binding')
39
+ for (var cmp of cmps) {
40
+ var id = cmp.getAttribute('id')
41
+ var componentname = cmp.getAttribute('fgta5-component')
42
+ var binding = cmp.getAttribute('binding')
43
+ SearchParams[binding] = new $fgta5[componentname](id)
44
+ }
45
+
46
+ // generator-ext.mjs, export function initSearchParams(self, SearchParams) {}
47
+ // jangan exekusi langsung dari generatorExtender, karena akan error saat di rollup
48
+ if (typeof Extender.initSearchParams === 'function') {
49
+ Extender.initSearchParams(self, SearchParams)
50
+ } else {
51
+ console.warn(`'initSearchParams' tidak diimplementasikan di extender`)
52
+ }
53
+
54
+ } catch (err) {
55
+ throw err
56
+ } finally {
57
+ // load data
58
+ if (args.autoLoadGridData===true) {
59
+ loadData(self)
60
+ }
61
+ }
62
+
63
+
64
+ }
65
+
66
+ export async function render(self) {
67
+ console.log('generatorList render')
68
+ }
69
+
70
+ export function keyboardAction(self, actionName) {
71
+ if (actionName=='up') {
72
+ tbl.previousRecord()
73
+ } else if (actionName=='down') {
74
+ tbl.nextRecord()
75
+ } else if (actionName=='enter') {
76
+ const generatorEdit = self.Modules.generatorEdit
77
+ generatorEdit.Section.show({}, (evt)=>{
78
+ openRow(self, tbl.CurrentRow)
79
+ })
80
+ }
81
+ }
82
+
83
+ export async function loadData(self) {
84
+ await tbl.clear()
85
+ tbl_loadData(self)
86
+ }
87
+
88
+ export function getCurrentRow(self) {
89
+ return CurrentState.SelectedRow
90
+ }
91
+
92
+ function setCurrentRow(self, tr) {
93
+ CurrentState.SelectedRow = tr
94
+ }
95
+
96
+ export function addNewRow(self, data) {
97
+ const tr = tbl.addRow(data)
98
+ setCurrentRow(self, tr)
99
+ }
100
+
101
+ export function updateCurrentRow(self, data) {
102
+ const tr = CurrentState.SelectedRow
103
+
104
+ try {
105
+ tbl.updateRow(tr, data)
106
+ } catch (err) {
107
+ throw err
108
+ }
109
+ }
110
+
111
+ export function removeCurrentRow(self) {
112
+ const tr = CurrentState.SelectedRow
113
+ tr.remove()
114
+ }
115
+
116
+ export function selectNextRow(self) {
117
+ const tr = CurrentState.SelectedRow
118
+ if (tr.nextElementSibling) {
119
+ openRow(self, tr.nextElementSibling)
120
+ }
121
+ }
122
+
123
+ export function selectPreviousRow(self) {
124
+ const tr = CurrentState.SelectedRow
125
+ if (tr.previousElementSibling) {
126
+ openRow(self, tr.previousElementSibling)
127
+ }
128
+ }
129
+
130
+
131
+ async function openRow(self, tr) {
132
+ const keyvalue = tr.getAttribute('keyvalue')
133
+ const key = tr.getAttribute('key')
134
+
135
+ const generatorEdit = self.Modules.generatorEdit
136
+
137
+ try {
138
+ setCurrentRow(self, tr)
139
+ CurrentState.SelectedRow.keyValue = keyvalue
140
+ CurrentState.SelectedRow.key = key
141
+ await generatorEdit.openSelectedData(self, {key:key, keyvalue:keyvalue})
142
+ } catch (err) {
143
+ console.error(err)
144
+ await $fgta5.MessageBox.error(err.message)
145
+
146
+ setCurrentRow(self, null)
147
+ CurrentSection.show() // kembalikan ke list kalau error saat buka data
148
+ }
149
+ }
150
+
151
+
152
+ async function tbl_nextdata(self, evt) {
153
+ const criteria = evt.detail.criteria
154
+ const limit = evt.detail.limit
155
+ const offset = evt.detail.nextoffset
156
+ const sort = evt.detail.sort
157
+
158
+ await tbl_loadData(self, {criteria, limit, offset, sort})
159
+ tbl.scrollToFooter()
160
+ }
161
+
162
+ async function tbl_sorting(self, evt) {
163
+ tbl.clear()
164
+ const sort = evt.detail.sort
165
+ const criteria = evt.detail.Criteria
166
+ tbl_loadData(self, {criteria, sort})
167
+ }
168
+
169
+ async function tbl_cellclick(self, evt) {
170
+ if (Module.isMobileDevice()) {
171
+ await tbl_celldblclick(self, evt)
172
+ }
173
+ }
174
+
175
+ async function tbl_celldblclick(self, evt) {
176
+ const tr = evt.detail.tr
177
+
178
+ const generatorEdit = self.Modules.generatorEdit
179
+ generatorEdit.Section.show()
180
+
181
+ await openRow(self, tr)
182
+ }
183
+
184
+ async function btn_gridload_click(self, evt) {
185
+ setCurrentRow(self, null)
186
+ loadData(self)
187
+ }
188
+
189
+
190
+ async function tbl_loadData(self, params={}) {
191
+ console.log('loading generator data')
192
+ console.log(params)
193
+
194
+ const { criteria={}, limit=0, offset=0, sort={} } = params
195
+
196
+ // isi criteria
197
+ for (var key in SearchParams) {
198
+ var cmp = SearchParams[key]
199
+ var valid = cmp.validate()
200
+ if (!valid) {
201
+ console.error('ada yang belum diisi')
202
+ return false
203
+ }
204
+ criteria[key] = SearchParams[key].value
205
+ }
206
+
207
+ // cek sorting
208
+ if (sort===undefined) {
209
+ sort = tbl.getSort()
210
+ }
211
+
212
+ const args = {
213
+ columns: ['generator_id', 'generator_appname', 'generator_modulename'],
214
+ criteria: criteria,
215
+ offset: offset,
216
+ limit: limit,
217
+ sort: sort
218
+ }
219
+
220
+ let mask = $fgta5.Modal.createMask()
221
+
222
+ const apiList = new $fgta5.ApiEndpoint('/generator/list')
223
+ try {
224
+ const result = await apiList.execute(args)
225
+
226
+ // jika offset tidak didefinisikan, berarti start dari awal, table dikosongkan dahulua
227
+ // jika offset didefinisikan berarti request untuk halaman berikutnya
228
+ if (offset===undefined) {
229
+ tbl.clear()
230
+ }
231
+ tbl.addRows(result.data)
232
+ tbl.setNext(result.nextoffset, result.limit)
233
+
234
+ } catch (err) {
235
+ console.error(err)
236
+ $fgta5.MessageBox.error(err.message)
237
+ } finally {
238
+ apiList.dispose()
239
+ mask.close()
240
+ mask = null
241
+ }
242
+
243
+ }
@@ -0,0 +1,11 @@
1
+ .loginbox {
2
+ margin: 10px
3
+ }
4
+
5
+ .loginbox input {
6
+ margin-bottom: 5px;
7
+ }
8
+
9
+ .loginbox button {
10
+ margin-top: 5px;
11
+ }
@@ -0,0 +1,12 @@
1
+ <div class="loginbox">
2
+ <h1>Login</h1>
3
+ <div>
4
+ <input type="text" id="obj_username" placeholder="username">
5
+ </div>
6
+ <div>
7
+ <input type="password" id="obj_password" placeholder="password">
8
+ </div>
9
+ <div>
10
+ <button id="btn_login">Login</button>
11
+ </div>
12
+ </div>
@@ -0,0 +1,111 @@
1
+ const Context = {}
2
+ const btn_login = document.getElementById('btn_login')
3
+ const obj_username = document.getElementById('obj_username')
4
+ const obj_password = document.getElementById('obj_password')
5
+
6
+ // need test direct open
7
+ // https://core-dev.transfashion.id/?nexturl=https://ent-dev.transfashion.id/sitetype&id=STO
8
+ // skenario: buka link di atas dalam kondisi belum login, setelah login, diredirect lagi ke halaman di atas
9
+
10
+
11
+ export default class extends Module {
12
+ constructor() {
13
+ super()
14
+ }
15
+
16
+ async main(args={}) {
17
+
18
+ console.log('initializing module...')
19
+
20
+ sessionStorage.removeItem('nextmodule');
21
+ btn_login.addEventListener('click', (evt)=>{
22
+ btn_login_click(self, evt)
23
+ })
24
+
25
+ obj_username.addEventListener('keypress', evt=>{
26
+ const key = evt.key.toLowerCase()
27
+ if (key=='enter' && obj_username.value.trim()!='') {
28
+ obj_password.focus()
29
+ }
30
+ })
31
+
32
+ obj_password.addEventListener('keypress', evt=>{
33
+ const key = evt.key.toLowerCase()
34
+ if (key=='enter' && obj_password.value.trim()!='') {
35
+ btn_login.click()
36
+ }
37
+ })
38
+
39
+ setTimeout(()=>{
40
+ obj_username.focus()
41
+ }, 500)
42
+
43
+
44
+ try {
45
+ // inisiasi sisi server
46
+ try {
47
+ const result = await Module.apiCall(`/login/init`, { })
48
+ if (result.isLogin) {
49
+ location.href = '/'
50
+ }
51
+ } catch (err) {
52
+ throw err
53
+ }
54
+
55
+ } catch (err) {
56
+ throw err
57
+ }
58
+
59
+ }
60
+
61
+ }
62
+
63
+
64
+
65
+ async function btn_login_click(self, evt) {
66
+ console.log('login')
67
+ const username = obj_username.value
68
+ const password = obj_password.value
69
+
70
+ const queryString = window.location.search
71
+ const params = new URLSearchParams(queryString)
72
+ const nexturl = params.get('nexturl')
73
+ const nextmodule = params.get('nextmodule')
74
+
75
+ console.log(nexturl, nextmodule)
76
+
77
+ let mask = $fgta5.Modal.createMask()
78
+ try {
79
+ // login, tidak pakai self.apiCall, karena akan bypass session
80
+ const apiLogin = new $fgta5.ApiEndpoint('login/do-login')
81
+ const result = await apiLogin.execute({username, password})
82
+ if (result!=null) {
83
+ // login berhasil
84
+
85
+ // simpan flag login
86
+ sessionStorage.setItem('login', true);
87
+
88
+ if (nextmodule!=null) {
89
+ sessionStorage.setItem('nextmodule', nextmodule);
90
+ }
91
+
92
+ if (nexturl!=null) {
93
+ // redirect ke next url
94
+ sessionStorage.setItem('login_nexturl', nexturl);
95
+ location.href = nexturl
96
+ } else {
97
+ location.href = '/'
98
+ }
99
+ } else {
100
+ // login gagal
101
+ $fgta5.MessageBox.error('Login salah!')
102
+ }
103
+
104
+ } catch (err) {
105
+ console.log(err)
106
+ $fgta5.MessageBox.error(err.message)
107
+ } finally {
108
+ mask.close()
109
+ mask = null
110
+ }
111
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@agung_dhewe/webapps",
3
+ "version": "1.1.2",
4
+ "description": "library javascript (nodejs+express) untuk pengembangan applikasi web",
5
+ "type": "module",
6
+ "main": "./src/webapps.js",
7
+ "scripts": {
8
+ "generate": "node ./src/generator/trygenerate.js"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/agungdhewe/webapps.git"
13
+ },
14
+ "keywords": [
15
+ "webapps",
16
+ "postgresql"
17
+ ],
18
+ "author": "Agung Nugroho",
19
+ "license": "GPL-3.0-or-later",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/agungdhewe/webapps/issues"
25
+ },
26
+ "homepage": "https://github.com/agungdhewe/webapps#readme",
27
+ "dependencies": {
28
+ "@agung_dhewe/pgsqlc": "^1.1.5",
29
+ "bcrypt": "^6.0.0",
30
+ "connect-redis": "^9.0.0",
31
+ "cors": "^2.8.5",
32
+ "dotenv": "^16.5.0",
33
+ "ejs": "^3.1.10",
34
+ "express": "^5.1.0",
35
+ "express-session": "^1.18.1",
36
+ "jsonwebtoken": "^9.0.2",
37
+ "minio": "^8.0.6",
38
+ "multer": "^2.0.1",
39
+ "node-fetch": "^3.3.2",
40
+ "pg": "^8.16.2",
41
+ "pg-promise": "^11.14.0",
42
+ "redis": "^5.5.6",
43
+ "serve-favicon": "^2.5.0",
44
+ "ws": "^8.18.3"
45
+ }
46
+ }
@@ -0,0 +1,24 @@
1
+ import { Client } from 'minio';
2
+
3
+ const minioClient = new Client({
4
+ endPoint: 'localhost',
5
+ port: 9000,
6
+ useSSL: false,
7
+ accessKey: 'admin',
8
+ secretKey: 'gacutils13#!',
9
+ });
10
+
11
+ const uploadFile = async () => {
12
+ const bucketName = 'testupload';
13
+ const objectName = '123543/testfile.txt';
14
+ const filePath = './src/datalog.sql';
15
+
16
+ try {
17
+ await minioClient.fPutObject(bucketName, objectName, filePath);
18
+ console.log(`✅ File '${objectName}' uploaded to '${bucketName}'`);
19
+ } catch (error) {
20
+ console.error('❌ Upload failed:', error);
21
+ }
22
+ };
23
+
24
+ uploadFile();
package/src/api.js ADDED
@@ -0,0 +1,80 @@
1
+ export default class Api {
2
+ #req
3
+ #res
4
+ #next
5
+
6
+ constructor(req, res, next) {
7
+ this.#req = req
8
+ this.#res = res
9
+ this.#next = next
10
+ }
11
+
12
+ get req() { return this.#req }
13
+ get res() { return this.#res }
14
+ get next() { return this.#next }
15
+
16
+
17
+ static generateNotifierId(moduleName, str) {
18
+ return `${moduleName}-${str}`
19
+ }
20
+
21
+
22
+ static cekLogin(req) {
23
+ // jika req.session.user tidak ada datanya, berarti belum login
24
+ try {
25
+ if (req.session.user==null) {
26
+ throw new Error('belum login')
27
+ }
28
+
29
+ if (req.session.user.isLogin==null) {
30
+ throw new Error('belum login')
31
+ }
32
+
33
+ if (req.session.user.isLogin==false) {
34
+ throw new Error('belum login')
35
+ }
36
+ } catch (err) {
37
+ err.status = 401
38
+ throw err
39
+ }
40
+ }
41
+
42
+ static parseUploadData(data, files) {
43
+ const jsonFieldName = 'form-body-jsondata'
44
+ try {
45
+ if (files!=undefined) {
46
+ // ambil json data
47
+ const jsondata = files.filter(file => file.fieldname==jsonFieldName)
48
+ const jsonstring = jsondata[0].buffer.toString('utf-8')
49
+ Object.assign(data, JSON.parse(jsonstring).data)
50
+
51
+ const filelist = files.filter(file => file.fieldname!=jsonFieldName)
52
+ return filelist
53
+ }
54
+
55
+ return null
56
+ } catch (err) {
57
+ throw err
58
+ }
59
+ }
60
+
61
+
62
+ async handleRequest(methodName, body) {
63
+ try {
64
+ if (typeof this[methodName] === 'function') {
65
+ const result = await this[methodName](body)
66
+ return result
67
+ } else {
68
+ const errNotFound = new Error(`Method "${methodName}" tidak ditemukan.`)
69
+ errNotFound.code = 404
70
+ throw errNotFound
71
+ }
72
+ } catch (err) {
73
+ throw err
74
+ }
75
+ }
76
+
77
+
78
+ }
79
+
80
+