w-web-perm 1.0.48 → 1.0.49

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 (95) hide show
  1. package/.github/workflows/ci-test.yml +2 -2
  2. package/_gh-pages-deploy/.nojekyll +0 -0
  3. package/_gh-pages-deploy/WWebPerm.html +938 -0
  4. package/_gh-pages-deploy/WWebPerm.mjs.html +1228 -0
  5. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  6. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  7. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  8. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  9. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  10. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  11. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  12. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  13. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  14. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  15. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  16. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  17. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  18. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  19. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  20. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  21. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  22. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  23. package/_gh-pages-deploy/index.html +84 -0
  24. package/_gh-pages-deploy/scripts/collapse.js +39 -0
  25. package/_gh-pages-deploy/scripts/commonNav.js +28 -0
  26. package/_gh-pages-deploy/scripts/linenumber.js +25 -0
  27. package/_gh-pages-deploy/scripts/nav.js +12 -0
  28. package/_gh-pages-deploy/scripts/polyfill.js +4 -0
  29. package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +202 -0
  30. package/_gh-pages-deploy/scripts/prettify/lang-css.js +2 -0
  31. package/_gh-pages-deploy/scripts/prettify/prettify.js +28 -0
  32. package/_gh-pages-deploy/scripts/search.js +99 -0
  33. package/_gh-pages-deploy/styles/jsdoc.css +776 -0
  34. package/_gh-pages-deploy/styles/prettify.css +80 -0
  35. package/dist/css/app.d8b16216.css +1 -0
  36. package/dist/css/{chunk-vendors.f149e124.css → chunk-vendors.2d3ef2ba.css} +1 -1
  37. package/dist/index.tmp +2 -2
  38. package/dist/js/app-legacy.fb48310a.js +1 -0
  39. package/dist/js/app.fb48310a.js +1 -0
  40. package/dist/js/chunk-vendors-legacy.8fdd4435.js +21 -0
  41. package/dist/js/chunk-vendors.8fdd4435.js +21 -0
  42. package/dist/w-web-perm.umd.js +2 -2
  43. package/dist/w-web-perm.umd.js.map +1 -1
  44. package/docs/WWebPerm.html +2 -2
  45. package/docs/WWebPerm.mjs.html +138 -199
  46. package/docs/index.html +1 -1
  47. package/package.json +15 -11
  48. package/public/index.html +2 -2
  49. package/server/WWebPerm.mjs +137 -198
  50. package/server/procCore.mjs +169 -0
  51. package/server/procLang.mjs +197 -0
  52. package/server/procStaInfor.mjs +118 -0
  53. package/server/provideTabs.mjs +1 -1
  54. package/server/srLog.mjs +30 -0
  55. package/server/staLogs/staEvent.callWorker.mjs +46 -0
  56. package/server/staLogs/staEvent.mjs +116 -0
  57. package/server/staLogs/staEvent.shellWorker.mjs +19 -0
  58. package/server/staLogs/staEventTable.mjs +100 -0
  59. package/server/staLogs/test_staEvent.mjs +22 -0
  60. package/settings.json +40 -0
  61. package/src/components/Common/CheckYes.vue +18 -1
  62. package/src/components/Layout.vue +1 -1
  63. package/src/components/LayoutContent.vue +13 -1
  64. package/src/components/LayoutContentGrups.vue +32 -23
  65. package/src/components/LayoutContentPemis.vue +32 -23
  66. package/src/components/LayoutContentStaInfor.vue +536 -0
  67. package/src/components/LayoutContentTargets.vue +32 -23
  68. package/src/components/LayoutContentUsers.vue +32 -23
  69. package/src/components/LayoutState.vue +5 -0
  70. package/src/components/VeCgrups.vue +12 -3
  71. package/src/components/VeCpemis.vue +12 -3
  72. package/src/components/VeCrules.vue +12 -3
  73. package/src/components/VeGrupBlngUsers.vue +18 -6
  74. package/src/components/VePemiBlngGrups.vue +18 -6
  75. package/src/getPerm.mjs +7 -17
  76. package/src/getPermUserInfor.mjs +8 -18
  77. package/src/main.js +1 -0
  78. package/src/plugins/mShare.mjs +8 -13
  79. package/src/plugins/mUI.mjs +11 -0
  80. package/srv.mjs +76 -101
  81. package/tableTags.json +1 -1
  82. package/db/wperm/grups/data.mdb +0 -0
  83. package/db/wperm/grups/lock.mdb +0 -0
  84. package/db/wperm/pemis/data.mdb +0 -0
  85. package/db/wperm/pemis/lock.mdb +0 -0
  86. package/db/wperm/targets/data.mdb +0 -0
  87. package/db/wperm/targets/lock.mdb +0 -0
  88. package/db/wperm/users/data.mdb +0 -0
  89. package/db/wperm/users/lock.mdb +0 -0
  90. package/dist/css/app.30e81bfe.css +0 -1
  91. package/dist/js/app-legacy.3324392e.js +0 -1
  92. package/dist/js/app.3324392e.js +0 -1
  93. package/dist/js/chunk-vendors-legacy.e8703728.js +0 -21
  94. package/dist/js/chunk-vendors.e8703728.js +0 -21
  95. package/test/getUserRules.test.mjs +0 -899
@@ -0,0 +1,1228 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>WWebPerm.mjs - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+
18
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
19
+ </head>
20
+ <body>
21
+
22
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
23
+ <label for="nav-trigger" class="navicon-button x">
24
+ <div class="navicon"></div>
25
+ </label>
26
+
27
+ <label for="nav-trigger" class="overlay"></label>
28
+
29
+ <nav >
30
+
31
+
32
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul>
33
+
34
+ </nav>
35
+
36
+ <div id="main">
37
+
38
+ <h1 class="page-title">WWebPerm.mjs</h1>
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+ <section>
47
+ <article>
48
+ <pre class="prettyprint source linenums"><code>import path from 'path'
49
+ import fs from 'fs'
50
+ import get from 'lodash-es/get.js'
51
+ import each from 'lodash-es/each.js'
52
+ import map from 'lodash-es/map.js'
53
+ import keys from 'lodash-es/keys.js'
54
+ import size from 'lodash-es/size.js'
55
+ import join from 'lodash-es/join.js'
56
+ import iseobj from 'wsemi/src/iseobj.mjs'
57
+ import isestr from 'wsemi/src/isestr.mjs'
58
+ import ispint from 'wsemi/src/ispint.mjs'
59
+ import isearr from 'wsemi/src/isearr.mjs'
60
+ import isErr from 'wsemi/src/isErr.mjs'
61
+ import isfun from 'wsemi/src/isfun.mjs'
62
+ import ispm from 'wsemi/src/ispm.mjs'
63
+ import cint from 'wsemi/src/cint.mjs'
64
+ import j2o from 'wsemi/src/j2o.mjs'
65
+ import strleft from 'wsemi/src/strleft.mjs'
66
+ import strright from 'wsemi/src/strright.mjs'
67
+ import strdelright from 'wsemi/src/strdelright.mjs'
68
+ import pm2resolve from 'wsemi/src/pm2resolve.mjs'
69
+ import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
70
+ import fsIsFile from 'wsemi/src/fsIsFile.mjs'
71
+ import replace from 'wsemi/src/replace.mjs'
72
+ import strdelleft from 'wsemi/src/strdelleft.mjs'
73
+ import ltdtmapping from 'wsemi/src/ltdtmapping.mjs'
74
+ import pmKeyMutex from 'wsemi/src/pmKeyMutex.mjs'
75
+ import WServHapiServer from 'w-serv-hapi/src/WServHapiServer.mjs'
76
+ import WServOrm from 'w-serv-orm/src/WServOrm.mjs'
77
+ import ds from '../src/schema/index.mjs'
78
+ import { getUserRules } from '../src/plugins/mShare.mjs'
79
+ import procCore from './procCore.mjs'
80
+ import procLang from './procLang.mjs'
81
+ import srLogInit from './srLog.mjs'
82
+ import procStaInfor from './procStaInfor.mjs'
83
+
84
+
85
+ /**
86
+ * 權限伺服器
87
+ *
88
+ * @class
89
+ * @param {Function} WOrm 輸入資料庫ORM函數
90
+ * @param {String} url 輸入資料庫連線字串,例如w-orm-lmdb為'./db',或w-orm-mongodb為'mongodb://username:password@$127.0.0.1:27017'
91
+ * @param {String} db 輸入資料庫名稱字串
92
+ * @param {Function} getUserByToken 輸入處理函數,函數會傳入使用者token,通過此函數處理後並回傳使用者資訊物件,並至少須提供'id'、'email'、'name'、'isAdmin'欄位,且'isAdmin'限輸入'y'或'n',且輸入'y'時會複寫權限系統該使用者之'isAdmin'欄位值
93
+ * @param {Function} verifyClientUser 輸入驗證瀏覽使用者身份之處理函數,函數會傳入使用者資訊物件,通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false
94
+ * @param {Function} verifyAppUser 輸入驗證應用程序使用者身份之處理函數,函數會傳入使用者資訊物件,通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false
95
+ * @param {Object} [opt={}] 輸入設定物件,預設{}
96
+ * @param {Integer} [opt.serverPort=11006] 輸入伺服器通訊port,預設11006
97
+ * @param {Boolean} [opt.useCheckUser=false] 輸入是否檢查使用者資訊布林值,預設false
98
+ * @param {Function} [opt.getUserById=null] 輸入當useCheckUser=true時依照使用者ID取得使用者資訊物件函數,預設null
99
+ * @param {Boolean} [opt.useExcludeWhenNotAdmin=false] 輸入使用ORM的select方法時是否自動刪除數據內isActive欄位之布林值,預設false
100
+ * @param {Object} [opt.webName={}] 輸入站台名稱物件,至少包含語系eng與cht鍵的名稱,預設{}
101
+ * @param {Object} [opt.webDescription={}] 輸入站台描述物件,至少包含語系eng與cht鍵的名稱,預設{}
102
+ * @param {String} [opt.webLogo=''] 輸入站台logo字串,採base64格式,預設''
103
+ * @param {String} [opt.subfolder=''] 輸入站台所在子目錄字串,提供站台位於內網採反向代理進行服務時,故需支援位於子目錄情形,預設''
104
+ * @param {String} [opt.urlRedirect=''] 輸入錯誤時自動轉址字串,提供站台例如無法登入或驗證失敗時須自動轉址,預設''
105
+ * @param {String} [opt.mappingBy='email'] 輸入外部系統識別使用者token後所提供之資料物件,與權限系統之使用者資料物件,兩者間查找之對應欄位,可選'id'、'email'、'name',預設'email'
106
+ * @returns {Object} 回傳物件,其內server為hapi伺服器實體,wsrv為w-converhp的伺服器事件物件,wsds為w-serv-webdata的伺服器事件物件,可監聽error事件
107
+ * @example
108
+ *
109
+ * import WOrm from 'w-orm-lmdb/src/WOrmLmdb.mjs'
110
+ * import WWebPerm from './server/WWebPerm.mjs'
111
+ * import getSettings from './g.getSettings.mjs'
112
+ *
113
+ *
114
+ * //st
115
+ * let st = getSettings()
116
+ *
117
+ * let url = st.dbUrl
118
+ * let db = st.dbName
119
+ * let opt = {
120
+ *
121
+ * useCheckUser: false,
122
+ * getUserById: null,
123
+ * useExcludeWhenNotAdmin: false,
124
+ *
125
+ * serverPort: 11006,
126
+ * subfolder: '', //mperm
127
+ * urlRedirect: 'https://www.google.com/', //本機測試時得先編譯, 再瀏覽: http://localhost:11006/
128
+ *
129
+ * webName: {
130
+ * 'eng': 'Permission Service',
131
+ * 'cht': '權限管理系統',
132
+ * },
133
+ * webDescription: {
134
+ * 'eng': 'A web service package for user permissions and management targets.',
135
+ * 'cht': 'A web service package for user permissions and management targets.',
136
+ * },
137
+ * webLogo: 'data:image/svg+xml;base64,...',
138
+ *
139
+ * }
140
+ *
141
+ * let getUserByToken = async (token) => {
142
+ * // return {} //測試無法登入
143
+ * if (token === '{token-for-application}') { //提供外部應用系統作為存取使用者
144
+ * return {
145
+ * id: 'id-for-application',
146
+ * name: 'application',
147
+ * email: 'application@example.com',
148
+ * isAdmin: 'y',
149
+ * }
150
+ * }
151
+ * if (token === 'sys') { //開發階段w-ui-loginout自動給予browser使用者(且位於localhost)的token為sys
152
+ * return {
153
+ * id: 'id-for-admin',
154
+ * name: 'tester',
155
+ * email: 'admin@example.com', //mappingBy為email, 開發階段時會使用email找到所建置之使用者資料
156
+ * isAdmin: 'y',
157
+ * }
158
+ * }
159
+ * console.log('invalid token', token)
160
+ * console.log('於生產環境時得加入SSO等驗證token機制')
161
+ * return {}
162
+ * }
163
+ *
164
+ * let verifyClientUser = (user, from) => {
165
+ * console.log('verifyClientUser/user', user)
166
+ * // return false //測試無法登入
167
+ * console.log('於生產環境時得加入限制瀏覽器使用者身份機制')
168
+ * return user.isAdmin === 'y' //測試僅系統管理者使用
169
+ * }
170
+ *
171
+ * let verifyAppUser = (user, from) => {
172
+ * console.log('verifyAppUser/user', user)
173
+ * // return false //測試無法登入
174
+ * console.log('於生產環境時得加入限制應用程式使用者身份機制')
175
+ * return user.isAdmin === 'y' //測試僅系統管理者使用
176
+ * }
177
+ *
178
+ * //WWebPerm
179
+ * let instWWebPerm = WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser, opt)
180
+ *
181
+ * instWWebPerm.on('error', (err) => {
182
+ * console.log(err)
183
+ * })
184
+ *
185
+ */
186
+ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser, opt = {}) {
187
+ let instWServHapiServer = null
188
+
189
+
190
+ //check WOrm
191
+ if (!isfun(WOrm)) {
192
+ console.log('invalid WOrm', WOrm)
193
+ throw new Error('invalid WOrm')
194
+ }
195
+
196
+
197
+ //check url
198
+ if (!isestr(url)) {
199
+ console.log('invalid url', url)
200
+ throw new Error('invalid url')
201
+ }
202
+
203
+
204
+ //check db
205
+ if (!isestr(db)) {
206
+ console.log('invalid db', db)
207
+ throw new Error('invalid db')
208
+ }
209
+
210
+
211
+ //check getUserByToken
212
+ if (!isfun(getUserByToken)) {
213
+ console.log('invalid getUserByToken', getUserByToken)
214
+ throw new Error('invalid getUserByToken')
215
+ }
216
+
217
+
218
+ //check verifyClientUser
219
+ if (!isfun(verifyClientUser)) {
220
+ console.log('invalid verifyClientUser', verifyClientUser)
221
+ throw new Error('invalid verifyClientUser')
222
+ }
223
+
224
+
225
+ //check verifyAppUser
226
+ if (!isfun(verifyAppUser)) {
227
+ console.log('invalid verifyAppUser', verifyAppUser)
228
+ throw new Error('invalid verifyAppUser')
229
+ }
230
+
231
+
232
+ //serverPort
233
+ let serverPort = get(opt, 'serverPort')
234
+ if (!ispint(serverPort)) {
235
+ serverPort = 11006
236
+ }
237
+ serverPort = cint(serverPort)
238
+
239
+
240
+ //useCheckUser
241
+ let useCheckUser = get(opt, 'useCheckUser', false)
242
+
243
+
244
+ //getUserById
245
+ let getUserById = get(opt, 'getUserById', null)
246
+
247
+
248
+ //useExcludeWhenNotAdmin
249
+ let useExcludeWhenNotAdmin = get(opt, 'useExcludeWhenNotAdmin', false)
250
+
251
+
252
+ //webName
253
+ let webName = get(opt, 'webName', {})
254
+
255
+
256
+ //webDescription
257
+ let webDescription = get(opt, 'webDescription', {})
258
+
259
+
260
+ //webLogo
261
+ let webLogo = get(opt, 'webLogo', '')
262
+
263
+
264
+ //subfolder
265
+ let subfolder = get(opt, 'subfolder', '')
266
+ if (isestr(subfolder)) {
267
+ if (strright(subfolder, 1) === '/') { //右邊不需要給「/」
268
+ subfolder = strdelright(subfolder, 1)
269
+ }
270
+ if (strleft(subfolder, 1) !== '/') { //左邊需要給「/」
271
+ subfolder = `/${subfolder}`
272
+ }
273
+ }
274
+
275
+
276
+ //urlRedirect
277
+ let urlRedirect = get(opt, 'urlRedirect', '')
278
+ // console.log('urlRedirect', urlRedirect)
279
+
280
+
281
+ //params
282
+ let showLanguage = get(opt, 'showLanguage', 'n')
283
+ let language = get(opt, 'language', 'eng')
284
+ let showModeEditTargets = get(opt, 'showModeEditTargets', 'n')
285
+ let showModeEditPemis = get(opt, 'showModeEditPemis', 'n')
286
+ let showModeEditGrups = get(opt, 'showModeEditGrups', 'n')
287
+ let showModeEditUsers = get(opt, 'showModeEditUsers', 'n')
288
+ let modeEditTargets = get(opt, 'modeEditTargets', 'n')
289
+ let modeEditPemis = get(opt, 'modeEditPemis', 'n')
290
+ let modeEditGrups = get(opt, 'modeEditGrups', 'n')
291
+ let modeEditUsers = get(opt, 'modeEditUsers', 'n')
292
+ let widthTargetId = get(opt, 'widthTargetId', '')
293
+ let widthTargetDescription = get(opt, 'widthTargetDescription', '')
294
+ let widthPemisName = get(opt, 'widthPemisName', '')
295
+ let widthPemisDescription = get(opt, 'widthPemisDescription', '')
296
+ let widthGrupsName = get(opt, 'widthGrupsName', '')
297
+ let widthGrupsDescription = get(opt, 'widthGrupsDescription', '')
298
+ let widthUsersName = get(opt, 'widthUsersName', '')
299
+ let widthUsersEmail = get(opt, 'widthUsersEmail', '')
300
+ let widthUsersDescription = get(opt, 'widthUsersDescription', '')
301
+
302
+
303
+ //mappingBy
304
+ let mappingBy = get(opt, 'mappingBy', '')
305
+ if (mappingBy !== 'id' &amp;&amp; mappingBy !== 'email' &amp;&amp; mappingBy !== 'name') {
306
+ mappingBy = 'id'
307
+ }
308
+ // console.log('mappingBy', mappingBy)
309
+
310
+
311
+ //kpLangExt
312
+ let kpLangExt = get(opt, 'kpLangExt', null)
313
+
314
+
315
+ //kpLang
316
+ let kpLang = procLang({ kpLangExt, webName, webDescription })
317
+
318
+
319
+ //srLog
320
+ let srLog = srLogInit(opt)
321
+
322
+
323
+ //WServOrm
324
+ let optWServOrm = {
325
+ useCheckUser,
326
+ getUserById,
327
+ useExcludeWhenNotAdmin,
328
+ }
329
+ let wp = {}
330
+ try {
331
+ wp = WServOrm(ds, WOrm, url, db, optWServOrm)
332
+ }
333
+ catch (err) {
334
+ console.log(err)
335
+ }
336
+ let { woItems, procOrm } = wp
337
+
338
+
339
+ //pmKeyMutex: per-key in-memory mutex, 同 key 序列化、不同 key 並行.
340
+ //perm 為「整表批次 diff」寫入, key 粒度為 {op}:{keyTable}, 防同表並行 race (lost update).
341
+ let kmx = pmKeyMutex()
342
+
343
+
344
+ //procCore: 整表批次 diff 寫入邏輯 (updateTabItems + updateTargets/Pemis/Grups/Users)
345
+ let pc = procCore(woItems, procOrm, { srLog, kmx })
346
+
347
+
348
+ //procStaInfor: 統計資訊, fdLog 對齊 srLog 使用同一目錄; mock 由 settings.staEventMock 注入(e2e 統計圖穩定用)
349
+ let psi = procStaInfor({ fdLog: './_logs', mock: get(opt, 'staEventMock', false) })
350
+
351
+
352
+ //getWebInfor
353
+ let getWebInfor = (userId) => {
354
+
355
+ //info
356
+ srLog.info({ event: 'getWebInfor-success', userId })
357
+
358
+ return {
359
+
360
+ // webName, //已併入kpLang
361
+ // webDescription, //已併入kpLang
362
+ webLogo,
363
+ // urlRedirect, //登入失敗就需要轉址, 故須通過html模板取代提供, 無法用api提供
364
+
365
+ showLanguage,
366
+ language,
367
+ kpLang,
368
+
369
+ showModeEditTargets,
370
+ showModeEditPemis,
371
+ showModeEditGrups,
372
+ showModeEditUsers,
373
+ modeEditTargets,
374
+ modeEditPemis,
375
+ modeEditGrups,
376
+ modeEditUsers,
377
+
378
+ widthTargetId,
379
+ widthTargetDescription,
380
+ widthPemisName,
381
+ widthPemisDescription,
382
+ widthGrupsName,
383
+ widthGrupsDescription,
384
+ widthUsersName,
385
+ widthUsersEmail,
386
+ widthUsersDescription,
387
+
388
+ }
389
+ }
390
+
391
+
392
+ // //getTargetsList
393
+ // let getTargetsList = async (userId) => {
394
+ // let rs = await woItems.targets.select()
395
+ // return rs
396
+ // }
397
+
398
+
399
+ // //getPemisList
400
+ // let getPemisList = async (userId) => {
401
+ // let rs = await woItems.pemis.select()
402
+ // return rs
403
+ // }
404
+
405
+
406
+ // //getGrupsList
407
+ // let getGrupsList = async (userId) => {
408
+ // let rs = await woItems.grups.select()
409
+ // return rs
410
+ // }
411
+
412
+
413
+ // //getUsersList
414
+ // let getUsersList = async (userId) => {
415
+ // let rs = await woItems.users.select()
416
+ // return rs
417
+ // }
418
+
419
+
420
+ //checkUser
421
+ let checkUser = async(user) => {
422
+ let id = get(user, 'id', '')
423
+ if (!isestr(id)) {
424
+ console.log('user', user)
425
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserId' })
426
+ return Promise.reject(`cannotGetUserId`)
427
+ }
428
+ let email = get(user, 'email', '')
429
+ if (!isestr(email)) {
430
+ console.log('user', user)
431
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserEmail' })
432
+ return Promise.reject(`cannotGetUserEmail`)
433
+ }
434
+ let name = get(user, 'name', '')
435
+ if (!isestr(name)) {
436
+ console.log('user', user)
437
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserName' })
438
+ return Promise.reject(`cannotGetUserName`)
439
+ }
440
+ let isAdmin = get(user, 'isAdmin', '')
441
+ if (isAdmin !== 'y' &amp;&amp; isAdmin !== 'n') {
442
+ console.log('user', user)
443
+ console.log('user.isAdmin is not y or n', user.isAdmin)
444
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserRole' })
445
+ return Promise.reject(`cannotGetUserRole`)
446
+ }
447
+ return true
448
+ }
449
+
450
+
451
+ //getTokenUser
452
+ let getTokenUser = async(token) => {
453
+ //基於token查找使用者, 會基於外部getUserByToken以及perm內部users進行查找並比對
454
+
455
+ //userSelf
456
+ let userSelf = null
457
+ if (isestr(token)) {
458
+ userSelf = getUserByToken(token)
459
+ if (ispm(userSelf)) {
460
+ userSelf = await userSelf
461
+ }
462
+ }
463
+ // console.log('userSelf', userSelf)
464
+
465
+ //check
466
+ if (!iseobj(userSelf)) {
467
+ console.log(`token`, token)
468
+ srLog.error({ event: 'getTokenUser-error', msg: 'cannotFindUserFromToken' })
469
+ return Promise.reject(`cannotFindUserFromToken`)
470
+ }
471
+
472
+ //check userSelf
473
+ await checkUser(userSelf)
474
+
475
+ //須反查perm內users, 提供正規化屬性
476
+ let vSelf = get(userSelf, mappingBy, '')
477
+ // console.log('vSelf', vSelf)
478
+
479
+ //check
480
+ if (!isestr(vSelf)) {
481
+ console.log('userSelf', userSelf)
482
+ console.log('mappingBy', mappingBy)
483
+ srLog.error({ event: 'getTokenUser-error', msg: 'cannotGetUserProp', mappingBy })
484
+ return Promise.reject(`cannotGetUserProp`)
485
+ }
486
+
487
+ //userFind
488
+ let userFind = await woItems.users.select({ [mappingBy]: vSelf, isActive: 'y' })
489
+ userFind = get(userFind, 0, null)
490
+ // console.log('userFind', userFind)
491
+
492
+ //check
493
+ if (!iseobj(userFind)) {
494
+ console.log('userSelf', userSelf)
495
+ console.log('mappingBy', mappingBy)
496
+ srLog.error({ event: 'getTokenUser-error', msg: 'cannotGetUserFromPerm', mappingBy })
497
+ return Promise.reject(`cannotGetUserFromPerm`)
498
+ }
499
+
500
+ //複寫isAdmin
501
+ let isAdminSrc = get(userSelf, 'isAdmin', '')
502
+ let isAdminSelf = get(userFind, 'isAdmin', '')
503
+ if (isAdminSrc !== isAdminSelf) {
504
+ userFind.isAdmin = isAdminSelf
505
+ }
506
+ // console.log('userFind(isAdmin)', userFind)
507
+
508
+ return userFind
509
+ }
510
+
511
+
512
+ //p
513
+ let p = {
514
+ checkToken: async(token) => {
515
+
516
+ //getUserByToken
517
+ let u = await getUserByToken(token)
518
+ // console.log('u', u)
519
+
520
+ //checkUser
521
+ await checkUser(u)
522
+
523
+ return true
524
+ },
525
+ }
526
+
527
+
528
+ //getAndVerifyClientUser
529
+ let getAndVerifyClientUser = async (token, from = '') => {
530
+ //基於token查找client使用者, 會基於外部getUserByToken以及perm內部users進行查找並比對
531
+
532
+ //getTokenUser
533
+ let user = await getTokenUser(token)
534
+
535
+ //verifyClientUser
536
+ let b = verifyClientUser(user, from)
537
+ if (ispm(b)) {
538
+ b = await b
539
+ }
540
+
541
+ //check
542
+ if (!b) {
543
+ console.log('user', user)
544
+ srLog.error({ event: 'getAndVerifyClientUser-error', msg: 'userNoPermission', from })
545
+ return Promise.reject(`userNoPermission`)
546
+ }
547
+
548
+ return user
549
+ }
550
+
551
+
552
+ //getAndVerifyAppUser
553
+ let getAndVerifyAppUser = async (token, from = '') => {
554
+ //基於token查找app使用者, 會基於外部getUserByToken進行查找, 故只要getUserByToken提供使用者即可, 可支援getUserByToken給予針對應用程式所產生之虛擬使用者
555
+
556
+ //user
557
+ let user = null
558
+ if (isestr(token)) {
559
+ user = getUserByToken(token)
560
+ if (ispm(user)) {
561
+ user = await user
562
+ }
563
+ }
564
+ // console.log('user', user)
565
+
566
+ //check
567
+ if (!iseobj(user)) {
568
+ console.log(`token`, token)
569
+ srLog.error({ event: 'getAndVerifyAppUser-error', msg: 'cannotFindUserFromToken' })
570
+ return Promise.reject(`cannotFindUserFromToken`)
571
+ }
572
+
573
+ //verifyAppUser
574
+ let b = verifyAppUser(user, from)
575
+ if (ispm(b)) {
576
+ b = await b
577
+ }
578
+
579
+ //check
580
+ if (!b) {
581
+ console.log('user', user)
582
+ srLog.error({ event: 'getAndVerifyAppUser-error', msg: 'userNoPermission', from })
583
+ return Promise.reject(`userNoPermission`)
584
+ }
585
+
586
+ return user
587
+ }
588
+
589
+
590
+ //parsePayload
591
+ let parsePayload = async (req) => {
592
+
593
+ //payload
594
+ let payload = get(req, 'payload')
595
+
596
+ //to obj
597
+ if (isestr(payload)) {
598
+ payload = j2o(payload)
599
+ }
600
+
601
+ //check
602
+ if (!iseobj(payload)) {
603
+ console.log('payload', payload)
604
+ srLog.error({ event: 'parsePayload-error', msg: 'invalidPayload' })
605
+ return Promise.reject(`invalidPayload`)
606
+ }
607
+
608
+ //from
609
+ let from = get(payload, 'from', '')
610
+
611
+ //check
612
+ if (!isestr(from)) {
613
+ console.log('payload', payload)
614
+ srLog.error({ event: 'parsePayload-error', msg: 'invalidFromInPayload' })
615
+ return Promise.reject(`invalidFromInPayload`)
616
+ }
617
+
618
+ //rows
619
+ let rows = get(payload, 'rows', [])
620
+
621
+ //check
622
+ if (!isearr(rows)) {
623
+ console.log('payload', payload)
624
+ srLog.error({ event: 'parsePayload-error', msg: 'invalidRowsInPayload' })
625
+ return Promise.reject(`invalidRowsInPayload`)
626
+ }
627
+
628
+ //inp
629
+ let inp = {
630
+ from,
631
+ rows,
632
+ }
633
+
634
+ return inp
635
+ }
636
+
637
+
638
+ //syncAndReplaceTabs
639
+ let syncAndReplaceTabs = async (userId, inp, keyTable) => {
640
+
641
+ //序列化同表之並行整表 delAll+insert: 防 lost update (同 keyTable 序列化, 不同表並行)
642
+ return await kmx('syncAndReplaceTabs:' + keyTable, async () => {
643
+
644
+ //from
645
+ let from = get(inp, 'from', '')
646
+ // console.log('from', from)
647
+
648
+ //check
649
+ if (!isestr(from)) {
650
+ console.log('inp', inp)
651
+ srLog.error({ event: 'syncAndReplaceTabs-error', msg: 'invalidFrom', keyTable })
652
+ return Promise.reject(`invalidFrom`)
653
+ }
654
+
655
+ //rows
656
+ let rows = get(inp, 'rows', [])
657
+ // console.log(keyTable, rows)
658
+
659
+ //check
660
+ if (!isearr(rows)) {
661
+ console.log('inp', inp)
662
+ console.log('keyTable', keyTable)
663
+ srLog.error({ event: 'syncAndReplaceTabs-error', msg: 'invalidRows', keyTable })
664
+ return Promise.reject(`invalidRows`)
665
+ }
666
+
667
+ //save from
668
+ rows = map(rows, (v, k) => {
669
+ // v.order = k + 1 //order大部分由外部給予, 不能複寫
670
+ v.from = from
671
+ return v
672
+ })
673
+
674
+ //ltdtmapping
675
+ rows = ltdtmapping(rows, ds[keyTable].keys)
676
+ // console.log('ltdtmapping rows', rows)
677
+
678
+ //delAll from
679
+ await woItems[keyTable].delAll({ from })
680
+
681
+ //insert
682
+ // let r = await woItems[keyTable].insert(rows)
683
+ let r = await procOrm(userId, keyTable, 'insert', rows) //須使用procOrm才有辦法自動給予相關欄位
684
+ // console.log('r', r)
685
+
686
+ return r
687
+
688
+ })
689
+ }
690
+
691
+
692
+ //getGenUserByKV
693
+ let getGenUserByKV = async(keyUser, valueUser) => {
694
+
695
+ //userFind
696
+ let userFind = await woItems.users.select({ [keyUser]: valueUser, isActive: 'y' })
697
+ userFind = get(userFind, 0, null)
698
+
699
+ //check
700
+ if (!iseobj(userFind)) {
701
+ return null
702
+ }
703
+
704
+ return userFind
705
+ }
706
+
707
+
708
+ //getGenUserByUserId
709
+ let getGenUserByUserId = async(userId) => {
710
+
711
+ //userFind
712
+ let userFind = await getGenUserByKV('id', userId)
713
+
714
+ //check
715
+ if (!iseobj(userFind)) {
716
+ return null
717
+ }
718
+
719
+ return userFind
720
+ }
721
+
722
+
723
+ //getGenUserAndRulesByUserId
724
+ let getGenUserAndRulesByUserId = async (userId) => {
725
+
726
+ //userFind
727
+ let userFind = await getGenUserByUserId(userId)
728
+ // console.log('userFind', userFind)
729
+
730
+ //grups
731
+ let grups = await woItems.grups.select()
732
+ // console.log('grups', grups)
733
+
734
+ //pemis
735
+ let pemis = await woItems.pemis.select()
736
+ // console.log('pemis', pemis)
737
+
738
+ //targets
739
+ let targets = await woItems.targets.select()
740
+ // console.log('targets', targets)
741
+
742
+ //getUserRules
743
+ let kur = getUserRules(userFind, grups, pemis, targets)
744
+ // console.log('getUserRules', kur)
745
+
746
+ //check
747
+ if (!iseobj(kur)) {
748
+ console.log('userId', userId)
749
+ srLog.error({ event: 'getGenUserAndRulesByUserId-error', msg: 'cannotGetUserRules', userId })
750
+ return Promise.reject(`cannotGetUserRules`)
751
+ }
752
+
753
+ //grupsNames
754
+ let grupsNames = map(get(kur, 'grups', []), 'name') //kur.grups僅會提供isActive='y', 故grupsNames為有效權限群組名稱
755
+ grupsNames = join(grupsNames, ';')
756
+
757
+ return {
758
+ user: {
759
+ ...userFind,
760
+ grupsNames,
761
+ },
762
+ // grups: get(kur, 'grups', []),
763
+ rules: get(kur, 'rules', []),
764
+ }
765
+ }
766
+
767
+
768
+ //pathStaticFiles
769
+ let pathStaticFiles = 'dist'
770
+ let npmPathStaticFiles = './node_modules/w-web-perm/dist'
771
+ if (fsIsFolder(npmPathStaticFiles)) {
772
+ pathStaticFiles = npmPathStaticFiles
773
+ }
774
+ // console.log('pathStaticFiles', pathStaticFiles)
775
+
776
+
777
+ //subfolder
778
+ let fnEntryIn = 'index.tmp'
779
+ let fnEntryOut = 'index.html'
780
+ try {
781
+ let fpEntryIn = path.resolve(pathStaticFiles, fnEntryIn)
782
+ if (!fsIsFile(fpEntryIn)) {
783
+ fpEntryIn = path.resolve(pathStaticFiles, fnEntryOut) //本機開發另使用html替代tmp
784
+ }
785
+ if (!fsIsFile(fpEntryIn)) {
786
+ console.log('fpEntryIn', fpEntryIn)
787
+ throw new Error(`invalid fpEntryIn`)
788
+ }
789
+ let fpEntryOut = path.resolve(pathStaticFiles, fnEntryOut)
790
+ let c = fs.readFileSync(fpEntryIn, 'utf8')
791
+ c = replace(c, '/mperm/', '{sfd}/') //方法同genEntry
792
+ c = replace(c, '{sfd}', subfolder)
793
+ c = replace(c, '{urlRedirect}', urlRedirect)
794
+ c = replace(c, '{language}', language)
795
+ fs.writeFileSync(fpEntryOut, c, 'utf8')
796
+ }
797
+ catch (err) {
798
+ console.log(err)
799
+ console.log(`can not generate ${fnEntryOut}`)
800
+ }
801
+
802
+
803
+ //apis
804
+ let apis = [
805
+
806
+ {
807
+ method: 'GET',
808
+ path: '/api/getUserByToken', //未登入主頁時需先檢測token, getUserByToken為w-ui-loginout預設值, 若要更改兩邊須同時修改
809
+ handler: async function (req, res) {
810
+ // console.log('getUserByToken', req)
811
+
812
+ async function core() {
813
+ //提供對象為browser使用者, 須先檢測token是否有效, 確認後回傳該使用者之資訊物件
814
+
815
+ //token
816
+ let token = get(req, 'query.token', '')
817
+ // console.log('token', token)
818
+
819
+ //check
820
+ if (!isestr(token)) {
821
+ console.log('req.query', get(req, 'query'))
822
+ console.log('token', token)
823
+ console.log('[API]getUserByToken/check token: invalid token')
824
+ srLog.error({ event: 'api/getUserByToken-error', msg: 'tokenNoPermission' })
825
+ return Promise.reject(`tokenNoPermission`)
826
+ }
827
+
828
+ //getAndVerifyClientUser
829
+ let user = await getAndVerifyClientUser(token, 'getUserByToken')
830
+ // console.log('user', user)
831
+
832
+ //check
833
+ if (!iseobj(user)) {
834
+ console.log('token', token)
835
+ console.log('[API]getUserByToken/check user: invalid user')
836
+ srLog.error({ event: 'api/getUserByToken-error', msg: 'tokenNoPermission' })
837
+ return Promise.reject(`tokenNoPermission`)
838
+ }
839
+
840
+ //info
841
+ srLog.info({ event: 'api/getUserByToken-success', userId: get(user, 'id', '') })
842
+
843
+ return user
844
+ }
845
+
846
+ //pm2resolve core
847
+ let r = await pm2resolve(core)() //w-ui-loginout接收已預設格式用pm2resolve轉過, 須另提取state進行判斷
848
+ if (isErr(r.msg)) {
849
+ r.msg = r.msg.message
850
+ }
851
+ // console.log('getUserByToken', r)
852
+
853
+ return r
854
+ },
855
+ },
856
+ {
857
+ method: 'GET',
858
+ path: '/api/getPerm',
859
+ handler: async function (req, res) {
860
+ // console.log('getPerm', req)
861
+
862
+ async function core() {
863
+ //提供對象為node與browser端, 須為client使用者, 須先檢測token是否有效, 再依照token取得使用者資訊物件, 再由其userId查詢回傳該使用者之權限資訊物件
864
+
865
+ //token
866
+ let token = get(req, 'query.token', '')
867
+ // console.log('token', token)
868
+
869
+ //check
870
+ if (!isestr(token)) {
871
+ console.log('req.query', get(req, 'query'))
872
+ console.log('token', token)
873
+ console.log('[API]getPerm/check token: invalid token')
874
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
875
+ return Promise.reject(`tokenNoPermission`)
876
+ }
877
+
878
+ //getAndVerifyClientUser, 發起token的所屬使用者, 驗證僅對client使用者, 不得使用app使用者
879
+ let userSelf = await getAndVerifyClientUser(token, 'getPerm')
880
+ // console.log('userSelf', userSelf)
881
+
882
+ //check
883
+ if (!iseobj(userSelf)) {
884
+ console.log('token', token)
885
+ console.log('[API]getPerm/check userSelf: invalid userSelf')
886
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
887
+ return Promise.reject(`tokenNoPermission`)
888
+ }
889
+
890
+ //userIdSelf, client使用者的userId
891
+ let userIdSelf = get(userSelf, 'id', '')
892
+ // console.log('userIdSelf', userIdSelf)
893
+
894
+ //check
895
+ if (!isestr(userIdSelf)) {
896
+ console.log('token', token)
897
+ console.log('userSelf', userSelf)
898
+ console.log('[API]getPerm/check userIdSelf: invalid userIdSelf')
899
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
900
+ return Promise.reject(`tokenNoPermission`)
901
+ }
902
+
903
+ //getGenUserAndRulesByUserId, 查找到的client使用者與權限
904
+ let userWithRulesSelf = await getGenUserAndRulesByUserId(userIdSelf)
905
+ // console.log('getGenUserAndRulesByUserId', r)
906
+
907
+ //check
908
+ if (!iseobj(userWithRulesSelf)) {
909
+ console.log('token', token)
910
+ console.log('userSelf', userSelf)
911
+ console.log('userIdSelf', userIdSelf)
912
+ console.log('[API]getPerm/check userWithRulesSelf: invalid userWithRulesSelf')
913
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
914
+ return Promise.reject(`tokenNoPermission`)
915
+ }
916
+
917
+ //info
918
+ srLog.info({ event: 'api/getPerm-success', userId: userIdSelf })
919
+
920
+ return userWithRulesSelf
921
+ }
922
+
923
+ //pm2resolve core
924
+ let r = await pm2resolve(core)()
925
+ if (isErr(r.msg)) {
926
+ r.msg = r.msg.message
927
+ }
928
+ // console.log('getPerm r', r)
929
+
930
+ return r
931
+ },
932
+ },
933
+ {
934
+ method: 'GET',
935
+ path: '/api/getPermUserInfor',
936
+ handler: async function (req, res) {
937
+ // console.log('getPermUserInfor', req)
938
+
939
+ async function core() {
940
+ //提供對象為node端, 須為app使用者, 須先檢測token是否有效, 再由其userId查詢回傳該使用者權限資訊物件
941
+
942
+ //tokenSelf
943
+ let tokenSelf = get(req, 'query.token', '')
944
+ // console.log('token', token)
945
+
946
+ //check
947
+ if (!isestr(tokenSelf)) {
948
+ console.log('req.query', get(req, 'query'))
949
+ console.log('[API]getPermUserInfor/check tokenSelf: invalid tokenSelf')
950
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'tokenNoPermission' })
951
+ return Promise.reject(`tokenNoPermission`)
952
+ }
953
+
954
+ //getAndVerifyAppUser, 發起token的所屬使用者, 驗證須為app使用者
955
+ let userSelf = await getAndVerifyAppUser(tokenSelf, 'getPermUserInfor')
956
+ // console.log('userSelf', userSelf)
957
+
958
+ //check
959
+ if (!iseobj(userSelf)) {
960
+ console.log('req.query', get(req, 'query'))
961
+ console.log('tokenSelf', tokenSelf)
962
+ console.log('[API]getPermUserInfor/check userSelf: invalid userSelf')
963
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'tokenNoPermission' })
964
+ return Promise.reject(`tokenNoPermission`)
965
+ }
966
+
967
+ //userIdFind, 欲查找使用者的userId
968
+ let userIdFind = get(req, 'query.userId', '')
969
+ // console.log('userIdFind', userIdFind)
970
+
971
+ //check
972
+ if (!isestr(userIdFind)) {
973
+ console.log('req.query', get(req, 'query'))
974
+ console.log('tokenSelf', tokenSelf)
975
+ console.log('[API]getPermUserInfor/check userIdFind: invalid userIdFind')
976
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'tokenNoPermission' })
977
+ return Promise.reject(`tokenNoPermission`)
978
+ }
979
+
980
+ //getGenUserAndRulesByUserId, 查找到的使用者與權限
981
+ let userWithRulesFind = await getGenUserAndRulesByUserId(userIdFind)
982
+ // console.log('getGenUserAndRulesByUserId', userWithRulesFind)
983
+
984
+ //check
985
+ if (!iseobj(userWithRulesFind)) {
986
+ console.log('userIdFind', userIdFind)
987
+ console.log('[API]getPermUserInfor/check userWithRulesFind: invalid userWithRulesFind')
988
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'userIdNoPermrules' })
989
+ return Promise.reject(`userIdNoPermrules`)
990
+ }
991
+
992
+ //info
993
+ srLog.info({ event: 'api/getPermUserInfor-success', userId: userIdFind })
994
+
995
+ return userWithRulesFind
996
+ }
997
+
998
+ //pm2resolve core
999
+ let r = await pm2resolve(core)() //w-ui-loginout接收已預設格式用pm2resolve轉過, 須另提取state進行判斷
1000
+ if (isErr(r.msg)) {
1001
+ r.msg = r.msg.message
1002
+ }
1003
+ // console.log('getPermUserInfor', r)
1004
+
1005
+ return r
1006
+ },
1007
+ },
1008
+ {
1009
+ method: 'POST',
1010
+ path: '/syncAndReplaceTabs',
1011
+ handler: async function (req, res) {
1012
+ // console.log('syncAndReplaceTabs', req)
1013
+ // console.log('syncAndReplaceTabs payload', req.payload)
1014
+
1015
+ async function core() {
1016
+ //提供對象為node使用者, 須為系統管理者, 須先檢測token是否有效, 再進行數據變更
1017
+
1018
+ //token
1019
+ let token = get(req, 'query.token', '')
1020
+
1021
+ //check
1022
+ if (!isestr(token)) {
1023
+ console.log('req.query', get(req, 'query'))
1024
+ console.log('token', token)
1025
+ console.log('[API]syncAndReplaceTabs/check token: invalid token')
1026
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1027
+ return Promise.reject(`tokenNoPermission`)
1028
+ }
1029
+
1030
+ //keyTable
1031
+ let keyTable = get(req, 'query.keyTable', '')
1032
+
1033
+ //check
1034
+ if (!isestr(keyTable)) {
1035
+ console.log('req.query', get(req, 'query'))
1036
+ console.log('keyTable', keyTable)
1037
+ console.log('[API]syncAndReplaceTabs/check keyTable: invalid keyTable')
1038
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1039
+ return Promise.reject(`tokenNoPermission`)
1040
+ }
1041
+
1042
+ //check keyTable
1043
+ let allowedTables = ['targets', 'pemis', 'grups', 'users']
1044
+ if (!allowedTables.includes(keyTable)) {
1045
+ console.log('[API]syncAndReplaceTabs/check keyTable: unexpected keyTable', keyTable)
1046
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'invalidKeyTable', keyTable })
1047
+ return Promise.reject(`invalidKeyTable`)
1048
+ }
1049
+
1050
+ //getAndVerifyAppUser
1051
+ let user = await getAndVerifyAppUser(token, 'syncAndReplaceTabs')
1052
+
1053
+ //check user
1054
+ if (!iseobj(user)) {
1055
+ console.log('token', token)
1056
+ console.log('[API]syncAndReplaceTabs/check user: invalid user')
1057
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1058
+ return Promise.reject(`tokenNoPermission`)
1059
+ }
1060
+
1061
+ //userId
1062
+ let userId = get(user, 'id', '')
1063
+
1064
+ //check userId
1065
+ if (!isestr(userId)) {
1066
+ console.log('token', token)
1067
+ console.log('user', user)
1068
+ console.log('[API]syncAndReplaceTabs/check userId: invalid userId')
1069
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1070
+ return Promise.reject(`tokenNoPermission`)
1071
+ }
1072
+
1073
+ //parsePayload
1074
+ let inp = await parsePayload(req)
1075
+
1076
+ //syncAndReplaceTabs
1077
+ let r = await syncAndReplaceTabs(userId, inp, keyTable)
1078
+
1079
+ //info
1080
+ srLog.info({ event: 'api/syncAndReplaceTabs-success', userId, keyTable })
1081
+
1082
+ return r
1083
+ }
1084
+
1085
+ //pm2resolve core
1086
+ let r = await pm2resolve(core)()
1087
+ if (isErr(r.msg)) {
1088
+ r.msg = r.msg.message
1089
+ }
1090
+ // console.log('syncAndReplaceTabs', r)
1091
+
1092
+ return r
1093
+ },
1094
+ },
1095
+ ]
1096
+
1097
+
1098
+ //tableNamesExec, tableNamesSync
1099
+ let tableNamesExec = keys(ds)
1100
+ // let tableNamesSync = filter(tableNamesExec, (v) => {
1101
+ // return strright(v, 5) !== 'Items'//不同步數據
1102
+ // })
1103
+ let tableNamesSync = tableNamesExec
1104
+
1105
+
1106
+ //WServHapiServer
1107
+ instWServHapiServer = new WServHapiServer({
1108
+ port: opt.serverPort,
1109
+ pathStaticFiles,
1110
+ apiName: 'api',
1111
+ apis,
1112
+ tokenType: 'Bearer',
1113
+ verifyConn: async ({ apiType, authorization, query, headers, req }) => {
1114
+ // console.log('verifyConn', `apiType[${apiType}]`, `authorization[${authorization}]`)
1115
+
1116
+ //token
1117
+ let token = strdelleft(authorization, 7) //刪除Bearer
1118
+ // console.log('token', token)
1119
+
1120
+ //check
1121
+ if (!isestr(token)) {
1122
+ console.log('apiType', apiType)
1123
+ console.log('authorization', authorization)
1124
+ console.log('invalid token')
1125
+ return false
1126
+ }
1127
+
1128
+ //checkToken
1129
+ let b = await p.checkToken(token)
1130
+ // console.log('b', b)
1131
+
1132
+ //ip, 對齊sso慣例x-forwarded-for取第1個, fallback到req remoteAddress, 取不到則略過
1133
+ let ip = get(headers, 'x-forwarded-for', '').split(',')[0].trim()
1134
+ if (!isestr(ip)) {
1135
+ ip = get(req, 'info.remoteAddress', '') || get(req, 'socket.remoteAddress', '') || get(req, 'connection.remoteAddress', '')
1136
+ }
1137
+
1138
+ //origin
1139
+ let origin = get(headers, 'origin', '')
1140
+
1141
+ //referer
1142
+ let referer = get(headers, 'referer', '')
1143
+
1144
+ //info
1145
+ srLog.info({ event: 'verifyConn', ok: b, apiType, ip, origin, referer })
1146
+
1147
+ return b
1148
+ },
1149
+ getUserIdByToken: async (token) => { //可使用async或sync函數
1150
+ // console.log('getUserIdByToken', token)
1151
+ let user = await getUserByToken(token)
1152
+ let userId = get(user, 'id', '')
1153
+ if (!isestr(userId)) {
1154
+ console.log('token', token)
1155
+ console.log('userId', userId)
1156
+ srLog.error({ event: 'getUserIdByToken-error', msg: 'cannotFindUserId' })
1157
+ return Promise.reject(`cannotFindUserId`)
1158
+ }
1159
+ return userId
1160
+ },
1161
+ corsOrigins: ['*'],
1162
+ useDbOrm: true,
1163
+ kpOrm: woItems,
1164
+ operOrm: procOrm, //procOrm的輸入為: userId, tableName, methodName, input
1165
+ tableNamesExec,
1166
+ methodsExec: ['select', 'insert', 'save', 'del', 'delAll'], //mix需於procOrm內註冊以提供
1167
+ tableNamesSync,
1168
+ kpFunExt: { //接收參數第1個為userId, 之後才是前端給予參數
1169
+
1170
+ getWebInfor,
1171
+
1172
+ // getTargetsList,
1173
+ // getPemisList,
1174
+ // getGrupsList,
1175
+ // getUsersList,
1176
+
1177
+ updateTargets: pc.updateTargets,
1178
+ updatePemis: pc.updatePemis,
1179
+ updateGrups: pc.updateGrups,
1180
+ updateUsers: pc.updateUsers,
1181
+
1182
+ getStaEvent: async (userId, timeLength, timeInterval) => {
1183
+ let rs = await psi.getStaEvent(userId, timeLength, timeInterval)
1184
+ srLog.info({ event: 'getStaEvent-success', userId })
1185
+ return rs
1186
+ },
1187
+
1188
+ getStaEventTable: async (userId) => {
1189
+ let rs = await psi.getStaEventTable(userId)
1190
+ srLog.info({ event: 'getStaEventTable-success', userId })
1191
+ return rs
1192
+ },
1193
+
1194
+ },
1195
+ fnTableTags: 'tableTags-web-perm.json',
1196
+ })
1197
+
1198
+
1199
+ return instWServHapiServer
1200
+ }
1201
+
1202
+
1203
+ export default WWebPerm
1204
+ </code></pre>
1205
+ </article>
1206
+ </section>
1207
+
1208
+
1209
+
1210
+
1211
+
1212
+
1213
+ </div>
1214
+
1215
+ <br class="clear">
1216
+
1217
+ <footer>
1218
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Jun 22 2026 15:47:48 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1219
+ </footer>
1220
+
1221
+ <script>prettyPrint();</script>
1222
+ <script src="scripts/polyfill.js"></script>
1223
+ <script src="scripts/linenumber.js"></script>
1224
+
1225
+
1226
+
1227
+ </body>
1228
+ </html>