@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,389 @@
1
+ import path from 'path';
2
+ import pgp from 'pg-promise'
3
+ import db from '../db.js'
4
+ import { workerData, parentPort } from 'worker_threads';
5
+ import { access, mkdir } from 'fs/promises';
6
+ import { constants } from 'fs';
7
+
8
+ import { isFileExist } from './helper.js'
9
+
10
+ import { createModuleRollup } from './createModuleRollup.js'
11
+ import { createModuleContext } from './createModuleContext.js'
12
+ import { createModuleExtenderMjs } from './createModuleExtenderMjs.js'
13
+ import { createModuleExtenderHtml } from './createModuleExtenderHtml.js'
14
+ import { createModuleEjs } from './createModuleEjs.js'
15
+ import { createModuleMjs } from './createModuleMjs.js'
16
+ import { createModuleHeaderListHtml } from './createModuleHeaderListHtml.js'
17
+ import { createModuleHeaderListMjs } from './createModuleHeaderListMjs.js'
18
+ import { createModuleHeaderEditHtml } from './createModuleHeaderEditHtml.js'
19
+ import { createModuleHeaderEditMjs } from './createModuleHeaderEditMjs.js'
20
+ import { createModuleDetilListHtml } from './createModuleDetilListHtml.js'
21
+ import { createModuleDetilListMjs } from './createModuleDetilListMjs.js'
22
+ import { createModuleDetilEditHtml } from './createModuleDetilEditHtml.js'
23
+ import { createModuleDetilEditMjs } from './createModuleDetilEditMjs.js'
24
+ import { createApiModule } from './createApiModule.js'
25
+ import { createApiExtenderModule } from './createApiExtenderModule.js'
26
+ import { createTable } from './createTable.js';
27
+ import { createInfoAboutExtender } from './createInfoAboutExtender.js';
28
+ import { createInfoLogs } from './createInfoLogs.js';
29
+ import { createInfoRecordExtender } from './createInfoRecordExtender.js';
30
+ import { createIcon } from './createIcon.js'
31
+ import { createProgramData } from './createProgramData.js'
32
+
33
+
34
+
35
+ const { generator_id, user_id, user_name, ipaddress, jeda } = workerData;
36
+
37
+
38
+ main(generator_id)
39
+
40
+
41
+ async function main(id) {
42
+ try {
43
+ const queryParams = {generator_id: id}
44
+ const sql = 'select generator_data from core."generator" where generator_id = \${generator_id}'
45
+ const data = await db.one(sql, queryParams);
46
+
47
+
48
+ // cek dahulu apakah directory tujuan benar
49
+ // console.log(data)
50
+
51
+
52
+ await generate(id, data.generator_data)
53
+
54
+
55
+ } catch (err) {
56
+ err.message = `Generator Worker: ${err.message}`
57
+ throw err
58
+ }
59
+ }
60
+
61
+ async function sleep(s) {
62
+ if (s==0) {
63
+ return
64
+ }
65
+
66
+ return new Promise(lanjut=>{
67
+ setTimeout(()=>{
68
+ lanjut()
69
+ }, s*1000)
70
+ })
71
+ }
72
+
73
+ async function generate(id, data) {
74
+
75
+ const now = new Date();
76
+
77
+ const options = {
78
+ day: 'numeric',
79
+ month: 'short',
80
+ year: 'numeric',
81
+ hour: '2-digit',
82
+ minute: '2-digit',
83
+ hour12: false,
84
+ };
85
+
86
+ const formattedTime = now.toLocaleString('en-GB', options).replace(',', '');
87
+
88
+
89
+ const context = {
90
+ id:id,
91
+ user_id: user_id,
92
+ user_name: user_name,
93
+ ipaddress: ipaddress,
94
+ title: data.title,
95
+ descr: data.description,
96
+ directory: data.directory,
97
+ appname: data.appname,
98
+ moduleName: data.name,
99
+ entities: data.entities,
100
+ icon: data.icon,
101
+ timeGenerated: formattedTime,
102
+ postMessage: (info) => {
103
+ parentPort.postMessage(info)
104
+ }
105
+ }
106
+
107
+ const jedaWaktu = jeda ?? 0
108
+
109
+
110
+
111
+
112
+ // tambahkan referensi ke entity detil
113
+ const entityHeader = context.entities['header']
114
+ const headerPkFieldName = entityHeader.pk
115
+ const headerItems = entityHeader.Items
116
+ for (var entityName in context.entities) {
117
+ // tambahkan jika bukan header
118
+ if (entityName!='header') {
119
+ const headerPK = structuredClone(headerItems[headerPkFieldName])
120
+ headerPK.Reference.pk = entityHeader.pk
121
+ headerPK.Reference.table = entityHeader.table
122
+ headerPK.Reference.bindingValue = entityHeader.pk
123
+ headerPK.input_disabled = true
124
+ context.entities[entityName].Items[entityHeader.pk] = headerPK
125
+ }
126
+ }
127
+
128
+
129
+ try {
130
+
131
+ await checkEntitiy(context)
132
+ // process.exit(0)
133
+
134
+
135
+ await prepareDirectory(context, {overwrite:true})
136
+ await sleep(jedaWaktu)
137
+
138
+
139
+
140
+ const iconFileName = await createIcon(context, {overwrite:true})
141
+
142
+ await createProgramData(context, {iconFileName})
143
+
144
+ await createTable(context, {overwrite:true})
145
+ await sleep(jedaWaktu)
146
+
147
+ await createApiModule(context, {overwrite:true})
148
+ await sleep(jedaWaktu)
149
+
150
+
151
+
152
+ await createModuleRollup(context, {overwrite:true})
153
+ await sleep(jedaWaktu)
154
+
155
+ await createModuleContext(context, {overwrite:true})
156
+ await sleep(jedaWaktu)
157
+
158
+
159
+
160
+ await createModuleEjs(context, {overwrite:true})
161
+ await sleep(jedaWaktu)
162
+
163
+
164
+ await createModuleMjs(context, {overwrite:true, iconFileName})
165
+ await sleep(jedaWaktu)
166
+
167
+
168
+
169
+ // Header
170
+ await createModuleHeaderListHtml(context, {overwrite:true})
171
+ await sleep(jedaWaktu)
172
+
173
+
174
+ await createModuleHeaderListMjs(context, {overwrite:true})
175
+ await sleep(jedaWaktu)
176
+
177
+
178
+ await createModuleHeaderEditHtml(context, {overwrite:true})
179
+ await sleep(jedaWaktu)
180
+
181
+
182
+ await createModuleHeaderEditMjs(context, {overwrite:true})
183
+ await sleep(jedaWaktu)
184
+
185
+
186
+
187
+ // Detils
188
+ await createModuleDetilListHtml(context, {overwrite:true})
189
+ await sleep(jedaWaktu)
190
+
191
+ await createModuleDetilListMjs(context, {overwrite:true})
192
+ await sleep(jedaWaktu)
193
+
194
+
195
+ await createModuleDetilEditHtml(context, {overwrite:true})
196
+ await sleep(jedaWaktu)
197
+
198
+ await createModuleDetilEditMjs(context, {overwrite:true})
199
+ await sleep(jedaWaktu)
200
+
201
+
202
+ await createInfoLogs(context, {overwrite:true})
203
+ await sleep(jedaWaktu)
204
+
205
+
206
+ // Extender
207
+ await createApiExtenderModule(context, {overwrite:false})
208
+ await sleep(jedaWaktu)
209
+
210
+ await createModuleExtenderHtml(context, {overwrite:false})
211
+ await sleep(jedaWaktu)
212
+
213
+ await createModuleExtenderMjs(context, {overwrite:false})
214
+ await sleep(jedaWaktu)
215
+
216
+ await createInfoAboutExtender(context, {overwrite:false})
217
+ await sleep(jedaWaktu)
218
+
219
+ await createInfoRecordExtender(context, {overwrite:false})
220
+ await sleep(jedaWaktu)
221
+
222
+
223
+
224
+
225
+ // Selesai
226
+ context.postMessage({message: `finish`, done:true})
227
+ } catch (err) {
228
+ throw err
229
+ }
230
+ }
231
+
232
+ async function prepareDirectory(context) {
233
+ const appname = context.appname
234
+ const moduleName = context.moduleName
235
+ const directory = context.directory
236
+
237
+
238
+ try {
239
+
240
+ context.postMessage({message: `preparing directory`})
241
+ // await sleep(1)
242
+
243
+ // cek jika directory project exists
244
+ const projectDirExists = await directoryExists(directory)
245
+ if (!projectDirExists) {
246
+ throw new Error(`directory tujuan '${directory}' tidak ditemukan`)
247
+ }
248
+
249
+ const moduleDir = path.join(directory, 'public', 'modules', moduleName)
250
+ const apiDir = path.join(directory, 'src', 'apis')
251
+ const apiExtenderDir = path.join(apiDir, 'extenders')
252
+
253
+ const moduleDirExists = await directoryExists(moduleDir)
254
+ if (!moduleDirExists) {
255
+ // direktori modul tidak ditemukan, buat dulu
256
+ context.postMessage({message: `creating new directory: '${moduleDir}`})
257
+ await mkdir(moduleDir, {});
258
+ // await sleep(1)
259
+ }
260
+
261
+ const apiDirExists = await directoryExists(apiDir)
262
+ if (!apiDirExists) {
263
+ throw new Error(`directory tujuan '${apiDir}' tidak ditemukan`)
264
+ }
265
+
266
+ const apiExtenderDirExists = await directoryExists(apiExtenderDir)
267
+ if (!apiExtenderDirExists) {
268
+ throw new Error(`directory tujuan '${apiExtenderDir}' tidak ditemukan`)
269
+ }
270
+
271
+
272
+ // cek apakah sudah di lock
273
+ const lockFile = path.join(moduleDir, `${moduleName}.lock`)
274
+ var fileExists = await isFileExist(lockFile)
275
+ if (fileExists) {
276
+ console.log("\n\n\x1b[1m\x1b[31mERROR\x1b[0m")
277
+ console.log('Module sudah di lock, tidak bisa digenerate ulang')
278
+ process.exit(1)
279
+ }
280
+
281
+
282
+ context.moduleDir = moduleDir
283
+ context.apiDir = apiDir
284
+ context.apiExtenderDir = apiExtenderDir
285
+ } catch (err) {
286
+ throw err
287
+ }
288
+ }
289
+
290
+
291
+
292
+ async function directoryExists(path) {
293
+ try {
294
+ await access(path, constants.F_OK);
295
+ return true;
296
+ } catch {
297
+ return false;
298
+ }
299
+ }
300
+
301
+ async function checkEntitiy(context) {
302
+ const apps = []
303
+ try {
304
+ const sql = "select * from core.apps"
305
+ const rows = await db.any(sql)
306
+ for (let row of rows) {
307
+ apps[row.apps_id] = row
308
+ }
309
+ } catch (err) {
310
+ throw err
311
+ }
312
+
313
+
314
+ // cek appname
315
+ if (apps[context.appname]==null) {
316
+ throw new Error(`App Name: '${context.appname}' tidak valid. Cek di data apps`)
317
+ }
318
+
319
+
320
+ // process.exit(1)
321
+
322
+ for (let entityName in context.entities) {
323
+ const entity = context.entities[entityName]
324
+ const entity_table = entity.table
325
+ const entity_pk = entity.pk
326
+ const Items = entity.Items
327
+
328
+ let pkExists = false
329
+
330
+ for (let fieldName in Items) {
331
+ const item = Items[fieldName]
332
+ const component = item.component
333
+
334
+ // Cek Primary Key
335
+ if (fieldName==entity_pk) {
336
+ pkExists = true
337
+ if (!item.showInForm) {
338
+ throw new Error(`Primary key '${fieldName}' pada entity '${entityName}' harus di embed di form. Apabila ingin menyembunyakannya, gunakan 'hidden' di Container CSS `)
339
+ }
340
+ }
341
+
342
+ // Cek combobox
343
+ if (component=='Combobox') {
344
+ // cek apakah konfig udah bener
345
+ const reference = item.Reference
346
+ const table = reference.table.trim()
347
+ const pk = reference.pk.trim()
348
+ const bindingValue = reference.bindingValue.trim()
349
+ const bindingText = reference.bindingText.trim()
350
+ const loaderApiModule = reference.loaderApiModule.trim()
351
+ const loaderApiPath = reference.loaderApiPath.trim()
352
+
353
+ if(table=='') {
354
+ throw new Error(`table reference Combobox '${fieldName}' di entity '${entityName}' tidak boleh kosong`)
355
+ }
356
+
357
+ if(pk=='') {
358
+ throw new Error(`PK untuk table reference Combobox '${fieldName}' di entity '${entityName}' tidak boleh kosong`)
359
+ }
360
+
361
+ if(bindingValue=='') {
362
+ throw new Error(`binding value untuk table reference Combobox '${fieldName}' di entity '${entityName}' tidak boleh kosong`)
363
+ }
364
+
365
+ if(bindingText=='') {
366
+ throw new Error(`binding value untuk table reference Combobox '${fieldName}' di entity '${entityName}' tidak boleh kosong`)
367
+ }
368
+
369
+ if(loaderApiModule=='') {
370
+ throw new Error(`loader API Name untuk table reference Combobox '${fieldName}' di entity '${entityName}' tidak boleh kosong`)
371
+ }
372
+
373
+ if (apps[loaderApiModule]==null) {
374
+ throw new Error(`loader API Name: '${loaderApiModule}' untuk table reference Combobox '${fieldName}' di entity '${entityName}' tidak valid. Cek di data apps`)
375
+ }
376
+
377
+ if(loaderApiPath=='') {
378
+ throw new Error(`loader API path untuk table reference Combobox '${fieldName}' di entity '${entityName}' tidak boleh kosong`)
379
+ }
380
+ }
381
+ }
382
+
383
+ if (!pkExists) {
384
+ throw new Error(`Primary key pada entity '${entityName}' belum didefinisikan`)
385
+ }
386
+
387
+
388
+ }
389
+ }
package/src/helper.js ADDED
@@ -0,0 +1,82 @@
1
+ import fs from 'fs/promises';
2
+ import * as path from 'node:path';
3
+ import ejs from 'ejs'
4
+ import context from './context.js'
5
+
6
+
7
+
8
+ export function kebabToCamel(str) {
9
+ return str
10
+ .split('-')
11
+ .map((part, index) =>
12
+ index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)
13
+ )
14
+ .join('');
15
+ }
16
+
17
+
18
+ export async function importApiModule(modulename, options={}) {
19
+ // jika mode debug,
20
+ // load api akan selalu dilakukan saat request (tanpa caching)
21
+
22
+
23
+ const cached = options.cached===true ? true : false
24
+ const apiDir = options.apiDir || path.join('.', 'apis')
25
+ const apiPath = path.join(apiDir, `${modulename}.api.js`)
26
+
27
+ if (cached) {
28
+ return (await import(apiPath)).default;
29
+ } else {
30
+ const fullPath = new URL(apiPath, import.meta.url).pathname;
31
+ const mtime = (await fs.stat(fullPath)).mtimeMs;
32
+ const freshUrl = `${fullPath}?v=${mtime}`;
33
+ const module = await import(freshUrl);
34
+
35
+ if (module.default===undefined) {
36
+ throw new Error(`modul api '${modulename}' tidak mempunyai default class untuk import`)
37
+ }
38
+
39
+ return module.default;
40
+ }
41
+ }
42
+
43
+
44
+
45
+
46
+ export async function isFileExists(filepath) {
47
+ try {
48
+ await fs.access(filepath);
49
+ return true
50
+ } catch (err) {
51
+ return false
52
+ }
53
+ }
54
+
55
+ export async function parseTemplate(tplFilePath, variables={}) {
56
+ const template = await fs.readFile(tplFilePath, 'utf-8');
57
+ const content = ejs.render(template, variables)
58
+ return content
59
+ }
60
+
61
+
62
+ export function createDefaultEjsVariable(req) {
63
+ const appName = req.app.locals.appConfig.appName || ''
64
+ const moduleName = req.params.modulename
65
+ const libDebug = path.join(context.getWebappsDirectory(), 'templates', '_lib_debug.ejs')
66
+ const libProduction = path.join(context.getWebappsDirectory(), 'templates', '_lib_production.ejs')
67
+ const fgta5jsDebugMode = req.app.locals.appConfig.fgta5jsDebugMode
68
+ const fgta5jsVersion = req.app.locals.appConfig.fgta5jsVersion
69
+ const appDebugMode = req.app.locals.appConfig.appDebugMode
70
+
71
+ const variables = {
72
+ appName,
73
+ moduleName,
74
+ libDebug,
75
+ libProduction,
76
+ fgta5jsDebugMode,
77
+ fgta5jsVersion,
78
+ appDebugMode
79
+ }
80
+
81
+ return variables
82
+ }
package/src/logger.js ADDED
@@ -0,0 +1,39 @@
1
+ import { dblog } from './db.js'
2
+
3
+
4
+ export default new (class {
5
+ async access(user, modulename, url, errormessage) {
6
+ console.log('logger access', modulename, url, errormessage)
7
+ }
8
+
9
+
10
+ async log(logdata) {
11
+ const { id, user_id, user_name, moduleName, action, tablename, executionTimeMs, remark, metadata, ipaddress=''} = logdata
12
+ const sql = `insert into datalog
13
+ (log_time, log_user_id, log_user_name, log_action, log_ipaddress, log_module, log_table, log_doc_id, log_remark, log_executiontime, log_metadata)
14
+ values
15
+ (now(), \${log_user_id}, \${log_user_name}, \${log_action}, \${log_ipaddress}, \${log_module}, \${log_table}, \${log_doc_id}, \${log_remark}, \${log_executiontime}, \${log_metadata})
16
+ RETURNING log_time
17
+ `
18
+ const variable = {
19
+ log_user_id: user_id,
20
+ log_user_name: user_name,
21
+ log_action: action,
22
+ log_ipaddress: ipaddress,
23
+ log_module: moduleName,
24
+ log_table: tablename,
25
+ log_doc_id: id,
26
+ log_remark: remark,
27
+ log_executiontime: executionTimeMs,
28
+ log_metadata: metadata
29
+ }
30
+
31
+ const ret = await dblog.oneOrNone(sql, variable)
32
+ return ret
33
+ }
34
+
35
+
36
+ })()
37
+
38
+
39
+
package/src/router.js ADDED
@@ -0,0 +1,84 @@
1
+ import ExpressServer from 'express'
2
+ import multer from 'multer';
3
+ import fs from 'fs/promises';
4
+ import * as path from 'node:path'
5
+ import * as http from 'node:http'
6
+ import * as helper from './helper.js'
7
+ import { fileURLToPath } from 'node:url';
8
+ import context from './context.js'
9
+
10
+ import { defaultRootIndex } from './routers/defaultRootIndex.js'
11
+ import { handleModuleNotfound } from './routers/handleModuleNotfound.js'
12
+ import { handleError } from './routers/handleError.js'
13
+ import { fileUploadApi } from './routers/fileUploadApi.js'
14
+ import { publicDownloadHandler, privateDownloadHandler } from './routers/downloadHandler.js'
15
+ import { defaultLoginPage } from './routers/defaultLoginPage.js'
16
+ import { defaultLoginAsset } from './routers/defaultLoginAsset.js'
17
+ import { defaultLoginApi } from './routers/defaultLoginApi.js'
18
+ import { generatorPage } from './routers/generatorPage.js'
19
+ import { generatorAsset } from './routers/generatorAsset.js'
20
+ import { generatorApi } from './routers/generatorApi.js'
21
+ import { modulePage } from './routers/modulePage.js'
22
+ import { moduleApi } from './routers/moduleApi.js'
23
+
24
+
25
+ export default {
26
+ createBasicRouter: () => { return createBasicRouter() }
27
+ }
28
+
29
+
30
+ export function uploader(req, res, next) {
31
+ if (req.is('multipart/form-data')) {
32
+ const upload = multer();
33
+ upload.any()(req, res, next);
34
+ } else {
35
+ next();
36
+ }
37
+ }
38
+
39
+
40
+
41
+ export function createBasicRouter() {
42
+ const router = ExpressServer.Router({ mergeParams: true });
43
+
44
+ // index
45
+ router.get('/', defaultRootIndex)
46
+
47
+
48
+ // upload
49
+ router.post('/upload', fileUploadApi)
50
+
51
+ // download
52
+ router.get('/download', publicDownloadHandler)
53
+ router.post('/download', privateDownloadHandler)
54
+
55
+
56
+ // login
57
+ router.get('/login', defaultLoginPage)
58
+ router.get('/login/:requestedAsset', defaultLoginAsset)
59
+ router.post('/login/:method', defaultLoginApi)
60
+
61
+ // generator
62
+ router.get('/generator', generatorPage)
63
+ router.get('/generator/:requestedAsset', generatorAsset)
64
+ router.post('/generator/:method', generatorApi)
65
+
66
+
67
+ // debug
68
+ // router.get('/debug/:modulename', modulePage)
69
+ // router.post('/debug/:modulename/:method', moduleApi)
70
+
71
+
72
+ // modul
73
+ router.get('/:modulename', modulePage)
74
+ router.post('/:modulename/:method', moduleApi)
75
+
76
+ return router
77
+ }
78
+
79
+
80
+
81
+
82
+
83
+
84
+
@@ -0,0 +1,29 @@
1
+ import * as helper from './../helper.js'
2
+ import { handleError } from './handleError.js'
3
+
4
+
5
+ export async function defaultLoginApi(req, res, next) {
6
+ const moduleName = 'login'
7
+ const methodName = req.params.method
8
+
9
+ try {
10
+
11
+ const ModuleClass = await helper.importApiModule(moduleName)
12
+ const method = helper.kebabToCamel(methodName);
13
+ if (ModuleClass===undefined) {
14
+ throw new Error(`invalid module: '${moduleName}'`)
15
+ }
16
+
17
+ const requestedBody = req.body
18
+ const module = new ModuleClass(req, res, next)
19
+ const result = await module.handleRequest(method, requestedBody)
20
+ const response = {
21
+ code: 0,
22
+ result: result
23
+ }
24
+ res.json(response)
25
+ } catch (err) {
26
+ handleError(err, req, res)
27
+ }
28
+
29
+ }
@@ -0,0 +1,18 @@
1
+ import context from './../context.js'
2
+ import * as helper from './../helper.js'
3
+ import * as path from 'node:path'
4
+ import { handleError } from './handleError.js'
5
+
6
+
7
+ export async function defaultLoginAsset(req, res, next) {
8
+ const __dirname = context.getWebappsDirectory()
9
+ const requestedFile = req.params.requestedAsset;
10
+ const filePath = path.join(__dirname, 'modules', 'login', requestedFile)
11
+
12
+ const assetExists = await helper.isFileExists(filePath)
13
+ if (assetExists) {
14
+ res.sendFile(filePath)
15
+ } else {
16
+ res.status(404).send(`'${requestedFile}' is not found`)
17
+ }
18
+ }
@@ -0,0 +1,36 @@
1
+ import context from './../context.js'
2
+ import * as helper from './../helper.js'
3
+ import * as path from 'node:path'
4
+ import { handleError } from './handleError.js'
5
+
6
+ export async function defaultLoginPage(req, res, next) {
7
+ const __dirname = context.getWebappsDirectory()
8
+
9
+ try {
10
+
11
+ const loginPagePath = path.join(__dirname, 'modules', 'login', 'login.html')
12
+
13
+ const variables = {
14
+ ...helper.createDefaultEjsVariable(req),
15
+ ...{
16
+ loginPagePath
17
+ }
18
+ }
19
+
20
+ const tplFilePath = path.join(__dirname, 'templates', 'login.page.ejs')
21
+ const content = await helper.parseTemplate(tplFilePath, variables)
22
+
23
+ res.status(200).send(content)
24
+ // res.status(200).send(`defaultLoginApi`)
25
+
26
+ } catch (err) {
27
+ // next(err)
28
+ handleError(err, req, res)
29
+ }
30
+
31
+
32
+
33
+ }
34
+
35
+
36
+
@@ -0,0 +1,16 @@
1
+ import context from './../context.js'
2
+ import * as helper from './../helper.js'
3
+ import * as path from 'node:path'
4
+
5
+
6
+ export async function defaultRootIndex(req, res, next) {
7
+ const variables = {
8
+ ...helper.createDefaultEjsVariable(req),
9
+ ...{
10
+
11
+ }
12
+ }
13
+ const tplFilePath = path.join(context.getWebappsDirectory(), 'templates', 'index.page.ejs')
14
+ const content = await helper.parseTemplate(tplFilePath, variables)
15
+ res.status(200).send(content)
16
+ }