sumba 0.0.1 → 0.1.1

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 (86) hide show
  1. package/bajo/config.json +48 -1
  2. package/bajo/helper/create-jwt-from-user-record.js +19 -0
  3. package/bajo/helper/get-user-from-username-password.js +18 -0
  4. package/bajo/helper/get-user.js +12 -0
  5. package/bajo/helper/has-column.js +10 -0
  6. package/bajo/helper/verify/api-key.js +40 -0
  7. package/bajo/helper/verify/basic.js +45 -0
  8. package/bajo/helper/verify/jwt.js +30 -0
  9. package/bajo/helper/verify/session.js +16 -0
  10. package/bajo/hook/bajo@after-init-bajo-web-mpa.js +5 -0
  11. package/bajo/hook/bajo@after-init-bajo-web-restapi.js +5 -0
  12. package/bajo/hook/bajoDb.SumbaUser@on-before-record-create.js +10 -0
  13. package/bajo/hook/bajoDb.SumbaUser@on-before-record-validation.js +25 -0
  14. package/bajo/hook/bajoDb@on-before-record-create.js +15 -0
  15. package/bajo/hook/bajoDb@on-before-record-find.js +23 -0
  16. package/bajo/hook/bajoDb@on-before-record-get.js +25 -0
  17. package/bajo/hook/bajoDb@on-before-record-remove.js +10 -0
  18. package/bajo/hook/bajoDb@on-before-record-update.js +10 -0
  19. package/bajo/hook/bajoWeb@after-boot-app.js +8 -0
  20. package/bajo/hook/bajoWeb@after-create-context.js +5 -0
  21. package/bajo/hook/bajoWeb@on-request.js +10 -0
  22. package/bajo/hook/bajoWebMpa@pre-parsing.js +33 -0
  23. package/bajo/hook/bajoWebRestapi@pre-parsing.js +10 -0
  24. package/bajo/hook/bajoWebStatic@pre-parsing.js +10 -0
  25. package/bajoAdmin/coll/site-setting.json +3 -0
  26. package/bajoAdmin/coll/site.json +8 -0
  27. package/bajoAdmin/coll/user-setting.json +3 -0
  28. package/bajoAdmin/coll/user.json +98 -0
  29. package/bajoAdmin/mpa/lib/pre-handler.js +11 -0
  30. package/bajoAdmin/mpa/route/userman/add.js +16 -0
  31. package/bajoAdmin/mpa/route/userman/def.json +7 -0
  32. package/bajoAdmin/mpa/route/userman/delete.js +12 -0
  33. package/bajoAdmin/mpa/route/userman/detail.js +15 -0
  34. package/bajoAdmin/mpa/route/userman/edit.js +16 -0
  35. package/bajoAdmin/mpa/route/userman/list.js +16 -0
  36. package/bajoDb/feature/address.js +46 -0
  37. package/bajoDb/feature/country.js +15 -0
  38. package/bajoDb/feature/lat-lng.js +19 -0
  39. package/bajoDb/feature/lat.js +13 -0
  40. package/bajoDb/feature/lng.js +13 -0
  41. package/bajoDb/feature/person-in-charge.js +25 -0
  42. package/bajoDb/feature/site-id.js +12 -0
  43. package/bajoDb/feature/social.js +23 -0
  44. package/bajoDb/feature/status.js +19 -0
  45. package/bajoDb/feature/ts.js +13 -0
  46. package/bajoDb/feature/user-id.js +13 -0
  47. package/bajoDb/fixture/site-setting.json +4 -0
  48. package/bajoDb/fixture/site.json +10 -0
  49. package/bajoDb/fixture/user-setting.json +5 -0
  50. package/bajoDb/fixture/user.json +11 -0
  51. package/bajoDb/i18n/en-US.json +6 -0
  52. package/bajoDb/i18n/id.json +6 -0
  53. package/bajoDb/schema/site-setting.json +12 -0
  54. package/bajoDb/schema/site.json +38 -0
  55. package/bajoDb/schema/user-setting.json +8 -0
  56. package/bajoDb/schema/user.json +56 -0
  57. package/bajoI18N/resource/id.json +25 -0
  58. package/bajoWebMpa/route/activation.js +25 -0
  59. package/bajoWebMpa/route/change-password.js +24 -0
  60. package/bajoWebMpa/route/forgot-password.js +8 -0
  61. package/bajoWebMpa/route/home.js +8 -0
  62. package/bajoWebMpa/route/profile.js +24 -0
  63. package/bajoWebMpa/route/signin.js +31 -0
  64. package/bajoWebMpa/route/signout.js +22 -0
  65. package/bajoWebMpa/route/signup.js +28 -0
  66. package/bajoWebMpa/template/default/activation.njk +19 -0
  67. package/bajoWebMpa/template/default/change-password.njk +24 -0
  68. package/bajoWebMpa/template/default/forgot-password.njk +20 -0
  69. package/bajoWebMpa/template/default/home.njk +8 -0
  70. package/bajoWebMpa/template/default/partial/pp.njk +16 -0
  71. package/bajoWebMpa/template/default/profile.njk +30 -0
  72. package/bajoWebMpa/template/default/signin.njk +21 -0
  73. package/bajoWebMpa/template/default/signout.njk +19 -0
  74. package/bajoWebMpa/template/default/signup-success.njk +9 -0
  75. package/bajoWebMpa/template/default/signup.njk +31 -0
  76. package/bajoWebRestapi/route/account/token/@type/create.js +58 -0
  77. package/lib/check-dark-mode.js +13 -0
  78. package/lib/check-lang.js +15 -0
  79. package/lib/check-site-id.js +36 -0
  80. package/lib/check-theme.js +9 -0
  81. package/lib/check-user-id.js +84 -0
  82. package/lib/collect-redirects.js +5 -0
  83. package/lib/collect-routes.js +57 -0
  84. package/package.json +5 -2
  85. package/sumba/bajoWebMpa@anonymous-routes.json +6 -0
  86. package/sumba/bajoWebMpa@secure-routes.json +5 -0
package/bajo/config.json CHANGED
@@ -1,3 +1,50 @@
1
1
  {
2
- "dependencies": ["bajo", "bajo-web"]
2
+ "multiSite": true,
3
+ "auth": {
4
+ "common": {
5
+ "apiKey": {
6
+ "type": "Bearer",
7
+ "qsKey": "apiKey",
8
+ "headerKey": "X-Sumba-ApiKey"
9
+ },
10
+ "basic": {
11
+ },
12
+ "jwt": {
13
+ "type": "Bearer",
14
+ "qsKey": "token",
15
+ "headerKey": "X-Sumba-Token",
16
+ "secret": "668de9cf57316c7dbf52f7ff7611c299",
17
+ "expiresIn": 604800000
18
+ },
19
+ "omitUserFields": ["password", "token"]
20
+ },
21
+ "bajoWebRestapi": {
22
+ "methods": ["basic", "apiKey", "jwt"]
23
+ },
24
+ "bajoWebMpa": {
25
+ "methods": ["session"]
26
+ },
27
+ "bajoWebStatic": {
28
+ "methods": ["basic", "apiKey", "jwt"],
29
+ "basic": {
30
+ "useUtf8": true,
31
+ "realm": "Protected Area",
32
+ "warningMessage": "Please authenticate yourself, thank you!"
33
+ }
34
+ }
35
+ },
36
+ "redirect": {
37
+ "signin": "sumba:/signin",
38
+ "signout": "sumba:/signout",
39
+ "home": "sumba:/home"
40
+ },
41
+ "userPassword": {
42
+ "minUppercase": 1,
43
+ "minLowercase": 1,
44
+ "minSpecialChar": 1,
45
+ "minNumeric": 1,
46
+ "noWhitespace": false,
47
+ "latinOnlyChars": false
48
+ },
49
+ "dependencies": ["bajo-db", "bajo-extra", "bajo-web", "bajo-common-db", "bajo-emitter"]
3
50
  }
@@ -0,0 +1,19 @@
1
+ async function createJwtFromUserRecord (rec) {
2
+ const { importPkg, getConfig, dayjs } = this.bajo.helper
3
+ const { hash } = this.bajoExtra.helper
4
+ const { get, pick } = await importPkg('lodash-es')
5
+ const fastJwt = await importPkg('bajo-extra:fast-jwt')
6
+ const { createSigner } = fastJwt
7
+
8
+ const cfg = getConfig('sumba')
9
+ const opts = pick(cfg.auth.common.jwt, ['expiresIn'])
10
+ opts.key = get(cfg, 'auth.common.jwt.secret')
11
+ const sign = createSigner(opts)
12
+ const apiKey = await hash(rec.password)
13
+ const payload = { uid: rec.id, apiKey }
14
+ const token = await sign(payload)
15
+ const expiresAt = dayjs().add(opts.expiresIn).toDate()
16
+ return { token, expiresAt }
17
+ }
18
+
19
+ export default createJwtFromUserRecord
@@ -0,0 +1,18 @@
1
+ const coll = 'SumbaUser'
2
+
3
+ async function getUserByUsernamePassword (username = '', password = '', req) {
4
+ const { error, importPkg } = this.bajo.helper
5
+ const { recordFind, validate } = this.bajoDb.helper
6
+ await validate({ username, password }, 'SumbaUser', { ns: ['sumba', 'bajoDb'], fields: ['username', 'password'] })
7
+ const bcrypt = await importPkg('bajo-extra:bcrypt')
8
+ const query = { username }
9
+ const rows = await recordFind(coll, { query }, { req, ignoreHidden: true })
10
+ if (rows.length === 0) throw error('Unknown username', { details: [{ field: 'username', error: 'Unknown username' }], statusCode: 401 })
11
+ const rec = rows[0]
12
+ if (rec.status !== 'ACTIVE') throw error('User is inactive or temporary disabled', { details: ['User is inactive or temporary disabled'], statusCode: 401 })
13
+ const verified = await bcrypt.compare(password, rec.password)
14
+ if (!verified) throw error('Invalid password', { details: [{ field: 'password', error: 'Invalid password' }], statusCode: 401 })
15
+ return rec
16
+ }
17
+
18
+ export default getUserByUsernamePassword
@@ -0,0 +1,12 @@
1
+ async function getUser (rec, safe = true) {
2
+ const { getConfig, importPkg } = this.bajo.helper
3
+ const { recordGet } = this.bajoDb.helper
4
+ const { omit, isString } = await importPkg('lodash-es')
5
+ const cfg = getConfig('sumba')
6
+ let user
7
+ if (isString(rec)) user = await recordGet('SumbaUser', rec, { skipHook: true })
8
+ else user = rec
9
+ return safe ? omit(user, cfg.auth.common.omitUserFields) : user
10
+ }
11
+
12
+ export default getUser
@@ -0,0 +1,10 @@
1
+ async function hasColumn (name, coll) {
2
+ const { importPkg } = this.bajo.helper
3
+ const { getInfo } = this.bajoDb.helper
4
+ const { find } = await importPkg('lodash-es')
5
+ const { schema } = await getInfo(coll)
6
+ const result = find(schema.properties, { name })
7
+ return !!result
8
+ }
9
+
10
+ export default hasColumn
@@ -0,0 +1,40 @@
1
+ export async function getSetting (type, source) {
2
+ const { importPkg, getConfig, defaultsDeep } = this.bajo.helper
3
+ const { get } = await importPkg('lodash-es')
4
+ const cfg = getConfig('sumba')
5
+ const setting = defaultsDeep(get(cfg, `auth.${source}.${type}`, {}), get(cfg, `auth.common.${type}`, {}))
6
+ if (type === 'basic') setting.type = 'Basic'
7
+ return setting
8
+ }
9
+
10
+ export async function getToken (type, req, source) {
11
+ const { importPkg } = this.bajo.helper
12
+ const { isEmpty } = await importPkg('lodash-es')
13
+ const setting = await getSetting.call(this, type, source)
14
+ let token = req.headers[setting.headerKey.toLowerCase()]
15
+ if (!['basic'].includes(type) && isEmpty(token)) token = req.query[setting.qsKey]
16
+ if (isEmpty(token)) {
17
+ const parts = (req.headers.authorization || '').split(' ')
18
+ if (parts[0] === setting.type) token = parts[1]
19
+ }
20
+ if (isEmpty(token)) return false
21
+ return token
22
+ }
23
+
24
+ async function verifyApiKey (ctx, req, reply, source) {
25
+ const { error } = this.bajo.helper
26
+ const { isMd5, hash } = this.bajoExtra.helper
27
+ const { getUser } = this.sumba.helper
28
+ const { recordFind } = this.bajoDb.helper
29
+ let token = await getToken.call(this, 'apiKey', req, source)
30
+ if (!isMd5(token)) return false
31
+ token = await hash(token)
32
+ const query = { token }
33
+ const rows = await recordFind('SumbaUser', { query }, { req })
34
+ if (rows.length === 0) throw error('Invalid api key provided', { statusCode: 401 })
35
+ if (rows[0].status !== 'ACTIVE') throw error('User is inactive or temporary disabled', { details: [{ field: 'status', error: 'inactive' }], statusCode: 401 })
36
+ req.user = await getUser(rows[0])
37
+ return true
38
+ }
39
+
40
+ export default verifyApiKey
@@ -0,0 +1,45 @@
1
+ import { getSetting } from './api-key.js'
2
+
3
+ async function setHeader (setting, reply) {
4
+ const { importPkg } = this.bajo.helper
5
+ const { isString } = await importPkg('lodash-es')
6
+ let header = setting.type
7
+ const exts = []
8
+ if (isString(setting.realm)) exts.push(`realm="${setting.realm}"`)
9
+ if (setting.useUtf8) exts.push('charset="UTF-8"')
10
+ if (exts.length > 0) header += ` ${exts.join(', ')}`
11
+ reply.header('WWW-Authenticate', header)
12
+ reply.code(401)
13
+ }
14
+
15
+ async function verifyBasic (ctx, req, reply, source) {
16
+ const { importPkg, print, error } = this.bajo.helper
17
+ const { getUserFromUsernamePassword } = this.sumba.helper
18
+ const { getUser } = this.sumba.helper
19
+ const { isEmpty } = await importPkg('lodash-es')
20
+ const setting = await getSetting.call(this, 'basic', source)
21
+ let authInfo
22
+ const parts = (req.headers.authorization || '').split(' ')
23
+ if (parts[0] === setting.type) authInfo = parts[1]
24
+ if (isEmpty(authInfo)) {
25
+ if (setting.realm) {
26
+ await setHeader.call(this, setting, reply)
27
+ throw error('print', { print: print.__(setting.warningMessage) })
28
+ } else return false
29
+ }
30
+ const decoded = Buffer.from(authInfo, 'base64').toString()
31
+ const [username, password] = decoded.split(':')
32
+ try {
33
+ const user = await getUserFromUsernamePassword(username, password, req)
34
+ req.user = await getUser(user)
35
+ } catch (err) {
36
+ if (err.statusCode === 401 && setting.realm) {
37
+ await setHeader.call(this, setting, reply)
38
+ return err.message
39
+ }
40
+ throw err
41
+ }
42
+ return true
43
+ }
44
+
45
+ export default verifyBasic
@@ -0,0 +1,30 @@
1
+ import { getToken, getSetting } from './api-key.js'
2
+
3
+ async function verifyJwt (ctx, req, reply, source) {
4
+ const { importPkg, error } = this.bajo.helper
5
+ const { recordGet } = this.bajoDb.helper
6
+ const { getUser } = this.sumba.helper
7
+ const { isEmpty } = await importPkg('lodash-es')
8
+ const fastJwt = await importPkg('bajo-extra:fast-jwt')
9
+ const { createVerifier } = fastJwt
10
+ const setting = await getSetting.call(this, 'jwt', source)
11
+ const token = await getToken.call(this, 'jwt', req, source)
12
+ if (isEmpty(token)) return false
13
+ const verifier = createVerifier({
14
+ key: setting.secret,
15
+ complete: true
16
+ })
17
+ const decoded = await verifier(token)
18
+ const id = decoded.payload.uid
19
+ try {
20
+ const rec = await recordGet('SumbaUser', id, { req })
21
+ if (!rec) throw error('Invalid token or token is expired', { statusCode: 401 })
22
+ if (rec.status !== 'ACTIVE') throw error('User is inactive or temporary disabled', { details: [{ field: 'status', error: 'inactive' }], statusCode: 401 })
23
+ req.user = await getUser(rec)
24
+ return true
25
+ } catch (err) {
26
+ return false
27
+ }
28
+ }
29
+
30
+ export default verifyJwt
@@ -0,0 +1,16 @@
1
+ async function verifySession (ctx, req, reply, source) {
2
+ const { getConfig, error } = this.bajo.helper
3
+ const { getUser } = this.sumba.helper
4
+ const { routePath } = this.bajoWeb.helper
5
+ const cfg = getConfig('sumba')
6
+ if (!req.session) return false
7
+ if (req.session.user) {
8
+ req.user = await getUser(req.session.user.id)
9
+ return true
10
+ }
11
+ const redir = routePath(cfg.redirect.signin, req)
12
+ req.session.ref = req.url
13
+ throw error('redirect', { redirect: redir })
14
+ }
15
+
16
+ export default verifySession
@@ -0,0 +1,5 @@
1
+ async function afterInitBajoWebMpa () {
2
+ this.bajoWebMpa.config.i18n.defaultNs.unshift('sumba')
3
+ }
4
+
5
+ export default afterInitBajoWebMpa
@@ -0,0 +1,5 @@
1
+ async function afterInitBajoWebRestapi () {
2
+ this.bajoWebRestapi.config.i18n.defaultNs.unshift('sumba')
3
+ }
4
+
5
+ export default afterInitBajoWebRestapi
@@ -0,0 +1,10 @@
1
+ async function bajoDbSiteUserOnBeforeRecordCreate (body, options) {
2
+ const { importPkg } = this.bajo.helper
3
+ const { isBcrypt, hash } = this.bajoExtra.helper
4
+ const { isEmpty } = await importPkg('lodash-es')
5
+ if (isEmpty(body.password)) return
6
+ if (!isBcrypt(body.password)) body.password = await hash(body.password, 'bcrypt')
7
+ body.token = await hash(await hash(body.password))
8
+ }
9
+
10
+ export default bajoDbSiteUserOnBeforeRecordCreate
@@ -0,0 +1,25 @@
1
+ import { joiPasswordExtendCore } from 'joi-password'
2
+
3
+ async function bajoDbSiteUserOnBeforeRecordValidation (body, options = {}) {
4
+ const { importPkg, getConfig } = this.bajo.helper
5
+ const { set } = await importPkg('lodash-es')
6
+ const joi = await importPkg('bajo-db:joi')
7
+ const cfg = getConfig('sumba')
8
+ const joiPassword = joi.extend(joiPasswordExtendCore)
9
+ let password = joiPassword
10
+ .string()
11
+ .min(8)
12
+ .max(50)
13
+ .required()
14
+ if (cfg.userPassword.minUppercase) password = password.minOfUppercase(cfg.userPassword.minUppercase)
15
+ if (cfg.userPassword.minLowercase) password = password.minOfLowercase(cfg.userPassword.minLowercase)
16
+ if (cfg.userPassword.minSpecialChar) password = password.minOfSpecialCharacters(cfg.userPassword.minSpecialChar)
17
+ if (cfg.userPassword.minNumeric) password = password.minOfNumeric(cfg.userPassword.minNumeric)
18
+ if (cfg.userPassword.noWhitespace) password = password.noWhiteSpaces()
19
+ if (cfg.userPassword.latinOnlyChars) password = password.onlyLatinCharacters()
20
+
21
+ const rule = { password }
22
+ set(options, 'validation.params.rule', rule)
23
+ }
24
+
25
+ export default bajoDbSiteUserOnBeforeRecordValidation
@@ -0,0 +1,15 @@
1
+ const bajoDbOnBeforeRecordCreate = {
2
+ level: 1000,
3
+ handler: async function (coll, body, options) {
4
+ const { importPkg } = this.bajo.helper
5
+ const { get } = await importPkg('lodash-es')
6
+ const { hasColumn } = this.sumba.helper
7
+ const item = { siteId: 'req.site.id', userId: 'req.user.id' }
8
+ for (const i in item) {
9
+ const rec = get(options, item[i])
10
+ if (rec && await hasColumn(i, coll)) body[i] = rec
11
+ }
12
+ }
13
+ }
14
+
15
+ export default bajoDbOnBeforeRecordCreate
@@ -0,0 +1,23 @@
1
+ const bajoDbOnBeforeRecordFind = {
2
+ level: 1000,
3
+ handler: async function (coll, filter, options) {
4
+ const { importPkg } = this.bajo.helper
5
+ const { isEmpty, cloneDeep, get, set } = await importPkg('lodash-es')
6
+ const { hasColumn } = this.sumba.helper
7
+ const item = { siteId: 'req.site.id', userId: 'req.user.id' }
8
+ for (const i in item) {
9
+ const rec = get(options, item[i])
10
+ if (rec && await hasColumn(i, coll)) {
11
+ filter.query = filter.query ?? {}
12
+ const old = cloneDeep(filter.query.$or)
13
+ if (old) {
14
+ filter.query = { $and: [old] }
15
+ filter.query.$and.push(set({}, i, rec))
16
+ } else filter.query[i] = rec
17
+ if (isEmpty(filter.query)) filter.query = undefined
18
+ }
19
+ }
20
+ }
21
+ }
22
+
23
+ export default bajoDbOnBeforeRecordFind
@@ -0,0 +1,25 @@
1
+ export async function checker (coll, id, req) {
2
+ const { importPkg, error } = this.bajo.helper
3
+ const { recordFind } = this.bajoDb.helper
4
+ const { get } = await importPkg('lodash-es')
5
+ const { hasColumn } = this.sumba.helper
6
+ const item = { siteId: 'site.id', userId: 'user.id' }
7
+ for (const i in item) {
8
+ const rec = get(req, item[i])
9
+ if (rec && await hasColumn(i, coll)) {
10
+ const filter = { query: { id }, limit: 1 }
11
+ filter.query[i] = rec
12
+ const rows = await recordFind(coll, filter)
13
+ if (rows.length === 0) throw error('Record \'%s@%s\' not found!', id, coll, { statusCode: 404 })
14
+ }
15
+ }
16
+ }
17
+
18
+ const bajoDbOnBeforeRecordGet = {
19
+ level: 1000,
20
+ handler: async function (coll, id, options) {
21
+ await checker.call(this, coll, id, options.req)
22
+ }
23
+ }
24
+
25
+ export default bajoDbOnBeforeRecordGet
@@ -0,0 +1,10 @@
1
+ import { checker } from './bajoDb@on-before-record-get.js'
2
+
3
+ const bajoDbOnBeforeRecordRemove = {
4
+ level: 1000,
5
+ handler: async function (coll, id, options) {
6
+ await checker.call(this, coll, id, options.req)
7
+ }
8
+ }
9
+
10
+ export default bajoDbOnBeforeRecordRemove
@@ -0,0 +1,10 @@
1
+ import { checker } from './bajoDb@on-before-record-get.js'
2
+
3
+ const bajoDbOnBeforeRecordUpdate = {
4
+ level: 1000,
5
+ handler: async function (coll, id, body, options) {
6
+ await checker.call(this, coll, id, options.req)
7
+ }
8
+ }
9
+
10
+ export default bajoDbOnBeforeRecordUpdate
@@ -0,0 +1,8 @@
1
+ import collectRoutes from '../../lib/collect-routes.js'
2
+
3
+ async function afterBootApp () {
4
+ await collectRoutes.call(this, 'secure')
5
+ await collectRoutes.call(this, 'anonymous')
6
+ }
7
+
8
+ export default afterBootApp
@@ -0,0 +1,5 @@
1
+ async function afterCreateContext (ctx) {
2
+ ctx.decorateRequest('user', null)
3
+ }
4
+
5
+ export default afterCreateContext
@@ -0,0 +1,10 @@
1
+ import checkSiteId from '../../lib/check-site-id.js'
2
+
3
+ const onRequest = {
4
+ level: 10,
5
+ handler: async function (ctx, req, reply) {
6
+ await checkSiteId.call(this, req, reply)
7
+ }
8
+ }
9
+
10
+ export default onRequest
@@ -0,0 +1,33 @@
1
+ import checkUserId from '../../lib/check-user-id.js'
2
+ import checkTheme from '../../lib/check-theme.js'
3
+ import checkLang from '../../lib/check-lang.js'
4
+ import checkDarkMode from '../../lib/check-dark-mode.js'
5
+
6
+ const onRequest = {
7
+ level: 10,
8
+ handler: async function (ctx, req, reply) {
9
+ const { routePath } = this.bajoWeb.helper
10
+ await checkDarkMode.call(this, req, reply)
11
+ await checkLang.call(this, req, reply)
12
+ await checkTheme.call(this, req, reply)
13
+ await checkUserId.call(this, req, reply, 'bajoWebMpa')
14
+ req.menu = req.menu ?? {}
15
+ if (req.user) {
16
+ req.menu.user = [
17
+ { value: routePath('sumba:/change-password', req), text: 'Change Password' },
18
+ { value: routePath('sumba:/profile', req), text: 'Your Profile' },
19
+ '-',
20
+ { value: routePath('sumba:/signout', req), text: 'Signout' }
21
+ ]
22
+ } else {
23
+ req.menu.user = [
24
+ { value: routePath('sumba:/signin', req), text: 'Signin' },
25
+ '-',
26
+ { value: routePath('sumba:/signup', req), text: 'Signup' },
27
+ { value: routePath('sumba:/forgot-password', req), text: 'Forgot Password' }
28
+ ]
29
+ }
30
+ }
31
+ }
32
+
33
+ export default onRequest
@@ -0,0 +1,10 @@
1
+ import checkUserId from '../../lib/check-user-id.js'
2
+
3
+ const onRequest = {
4
+ level: 10,
5
+ handler: async function (ctx, req, reply) {
6
+ await checkUserId.call(this, req, reply, 'bajoWebRestapi')
7
+ }
8
+ }
9
+
10
+ export default onRequest
@@ -0,0 +1,10 @@
1
+ import checkUserId from '../../lib/check-user-id.js'
2
+
3
+ const onRequest = {
4
+ level: 10,
5
+ handler: async function (ctx, req, reply) {
6
+ await checkUserId.call(this, req, reply, 'bajoWebStatic')
7
+ }
8
+ }
9
+
10
+ export default onRequest
@@ -0,0 +1,3 @@
1
+ {
2
+ "onMenu": false
3
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "onMenu": false,
3
+ "view": {
4
+ "list": {
5
+ "hidden": ["email", "picName", "picRole", "picPhone", "picEmail", "address1", "address2", "city", "zipCode", "provinceState", "country", "phone", "website"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "onMenu": false
3
+ }
@@ -0,0 +1,98 @@
1
+ {
2
+ "onMenu": false,
3
+ "view": {
4
+ "hidden": ["password", "token"],
5
+ "list": {
6
+ "hidden": ["address1", "address2", "zipCode", "provinceState", "country", "website"],
7
+ "defSort": "username:1"
8
+ },
9
+ "detail": {
10
+ "layouts": [{
11
+ "title": "Meta Info",
12
+ "fields": [
13
+ "createdAt;small:6,medium:6",
14
+ "updatedAt;small:6,medium:6",
15
+ "id;small:6,medium:4",
16
+ "siteId;small:6,medium:4",
17
+ "status;small:12,medium:4"
18
+ ]
19
+ }, {
20
+ "title": "Account",
21
+ "fields": [
22
+ "username;small:6,medium:6",
23
+ "email;small:6,medium:6",
24
+ "firstName;small:6,medium:6",
25
+ "lastName;small:6,medium:6"
26
+ ]
27
+ }, {
28
+ "title": "Address",
29
+ "fields": [
30
+ "address1",
31
+ "address2",
32
+ "city;small:6,medium:8",
33
+ "zipCode;small:6,medium:4",
34
+ "provinceState;small:6,medium:6",
35
+ "country;small:6,medium:6"
36
+ ]
37
+ }, {
38
+ "title": "Contact",
39
+ "fields": [
40
+ "phone;small:6,medium:6",
41
+ "website;small:6,medium:6"
42
+ ]
43
+ }, {
44
+ "title": "Social Media",
45
+ "fields": [
46
+ "twitter;small:6,medium:3",
47
+ "instagram;small:6,medium:3",
48
+ "facebook;small:6,medium:3",
49
+ "linkedIn;small:6,medium:3"
50
+ ]
51
+ }]
52
+ },
53
+ "edit": {
54
+ "layouts": [{
55
+ "title": "Meta Info",
56
+ "fields": [
57
+ "createdAt;small:6,medium:6;formPlaintext",
58
+ "updatedAt;small:6,medium:6;formPlaintext",
59
+ "id;small:6,medium:4;formPlaintext",
60
+ "siteId;small:6,medium:4",
61
+ "status;small:12,medium:4"
62
+ ]
63
+ }, {
64
+ "title": "Account",
65
+ "fields": [
66
+ "username;small:6,medium:6",
67
+ "email;small:6,medium:6",
68
+ "firstName;small:6,medium:6",
69
+ "lastName;small:6,medium:6"
70
+ ]
71
+ }, {
72
+ "title": "Address",
73
+ "fields": [
74
+ "address1",
75
+ "address2",
76
+ "city;small:6,medium:8",
77
+ "zipCode;small:6,medium:4",
78
+ "provinceState;small:6,medium:6",
79
+ "country;small:6,medium:6"
80
+ ]
81
+ }, {
82
+ "title": "Contact",
83
+ "fields": [
84
+ "phone;small:6,medium:6",
85
+ "website;small:6,medium:6"
86
+ ]
87
+ }, {
88
+ "title": "Social Media",
89
+ "fields": [
90
+ "twitter;small:6,medium:3",
91
+ "instagram;small:6,medium:3",
92
+ "facebook;small:6,medium:3",
93
+ "linkedIn;small:6,medium:3"
94
+ ]
95
+ }]
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,11 @@
1
+ async function preHandler (ctx, req, reply) {
2
+ const { importModule, getConfig } = this.bajo.helper
3
+ const cfg = getConfig('bajoAdmin', { full: true })
4
+ const buildCollMenu = await importModule(`${cfg.dir.pkg}/lib//build-coll-menu.js`)
5
+ const buildPagesMenu = await importModule(`${cfg.dir.pkg}/lib//build-pages-menu.js`)
6
+ req.menu = req.menu ?? {}
7
+ req.menu.coll = await buildCollMenu.call(this)
8
+ req.menu.pages = await buildPagesMenu.call(this)
9
+ }
10
+
11
+ export default preHandler
@@ -0,0 +1,16 @@
1
+ import preHandler from '../../lib/pre-handler.js'
2
+
3
+ const userman = {
4
+ title: 'User Manager',
5
+ preHandler,
6
+ method: ['GET', 'POST'],
7
+ handler: async function (ctx, req, reply) {
8
+ const { importModule, getConfig, readConfig, currentLoc } = this.bajo.helper
9
+ const { coll, tpl } = await readConfig(currentLoc(import.meta).dir + '/def.json')
10
+ const cfg = getConfig('bajoAdmin', { full: true })
11
+ const addHandler = await importModule(`${cfg.dir.pkg}/lib/crud/add-handler.js`)
12
+ return await addHandler.call(this, { ctx, req, reply, coll, tpl })
13
+ }
14
+ }
15
+
16
+ export default userman
@@ -0,0 +1,7 @@
1
+ {
2
+ "coll": "SumbaUser",
3
+ "tpl": {
4
+ "baseRoute": "bajoAdmin:/sumba/userman",
5
+ "baseId": "userman"
6
+ }
7
+ }
@@ -0,0 +1,12 @@
1
+ const userman = {
2
+ method: 'POST',
3
+ handler: async function (ctx, req, reply) {
4
+ const { importModule, getConfig, readConfig, currentLoc } = this.bajo.helper
5
+ const { coll, tpl } = await readConfig(currentLoc(import.meta).dir + '/def.json')
6
+ const cfg = getConfig('bajoAdmin', { full: true })
7
+ const deleteHandler = await importModule(`${cfg.dir.pkg}/lib/crud/delete-handler.js`)
8
+ return await deleteHandler.call(this, { ctx, req, reply, coll, tpl })
9
+ }
10
+ }
11
+
12
+ export default userman