sumba 1.1.12 → 1.1.13

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 (65) hide show
  1. package/bajo/hook/waibu-mpa.sumba@after-build-locals.js +2 -2
  2. package/bajo/hook/waibu@on-request.js +2 -3
  3. package/bajo/intl/en-US.json +4 -2
  4. package/bajo/intl/id.json +2 -0
  5. package/bajoTemplate/layout/centered.html +15 -0
  6. package/bajoTemplate/layout/default.html +14 -13
  7. package/bajoTemplate/partial/api-key-modal.html +1 -1
  8. package/bajoTemplate/partial/help/contact-form/form.html +20 -12
  9. package/bajoTemplate/partial/layout/footer.html +9 -10
  10. package/bajoTemplate/partial/list-item/change-password.html +1 -1
  11. package/bajoTemplate/partial/list-item/forgot-password.html +1 -1
  12. package/bajoTemplate/partial/list-item/goto-home.html +1 -1
  13. package/bajoTemplate/partial/list-item/member-links.html +7 -7
  14. package/bajoTemplate/partial/list-item/signin.html +1 -1
  15. package/bajoTemplate/partial/list-item/signout.html +1 -1
  16. package/bajoTemplate/partial/list-item/user-signup.html +1 -1
  17. package/bajoTemplate/partial/list-item/your-profile.html +1 -1
  18. package/bajoTemplate/partial/signin.html +7 -5
  19. package/bajoTemplate/partial/signout.html +7 -3
  20. package/bajoTemplate/partial/user/activation.html +4 -2
  21. package/bajoTemplate/partial/user/forgot-password.html +4 -2
  22. package/bajoTemplate/partial/user/signup/form.html +4 -2
  23. package/bajoTemplate/partial/user/signup/success.html +5 -3
  24. package/bajoTemplate/partial/{my-stuff → your-stuff}/change-password.html +2 -2
  25. package/bajoTemplate/partial/{my-stuff → your-stuff}/profile/edit.html +2 -2
  26. package/bajoTemplate/partial/{my-stuff → your-stuff}/profile/view.html +1 -1
  27. package/bajoTemplate/template/help/contact-form/form.html +0 -1
  28. package/bajoTemplate/template/help/contact-form/success.html +0 -1
  29. package/bajoTemplate/template/help/trouble-tickets/add.html +0 -1
  30. package/bajoTemplate/template/help/trouble-tickets/details.html +0 -1
  31. package/bajoTemplate/template/help/trouble-tickets/list.html +0 -1
  32. package/bajoTemplate/template/signin.html +1 -0
  33. package/bajoTemplate/template/signout.html +1 -0
  34. package/bajoTemplate/template/user/activation.html +1 -0
  35. package/bajoTemplate/template/user/forgot-password.html +1 -0
  36. package/bajoTemplate/template/user/fpl-invalid.html +1 -0
  37. package/bajoTemplate/template/user/fpl.html +1 -0
  38. package/bajoTemplate/template/user/signup/form.html +1 -0
  39. package/bajoTemplate/template/user/signup/success.html +1 -0
  40. package/bajoTemplate/template/your-stuff/change-password.html +3 -0
  41. package/bajoTemplate/template/your-stuff/profile/edit.html +3 -0
  42. package/bajoTemplate/template/your-stuff/profile/view.html +3 -0
  43. package/bajoTemplate/template/your-stuff/reset-api-key.html +3 -0
  44. package/lib/check-iconset.js +1 -1
  45. package/lib/check-team.js +1 -14
  46. package/lib/check-theme.js +2 -2
  47. package/lib/check-user-id.js +8 -12
  48. package/masohiSocketIo/middleware/server/auth.js +25 -0
  49. package/package.json +1 -1
  50. package/plugin/factory.js +112 -9
  51. package/sumba/route/secure.json +2 -2
  52. package/waibuMpa/route/signin.js +1 -1
  53. package/waibuMpa/route/signout.js +2 -4
  54. package/waibuMpa/route/{my-stuff → your-stuff}/change-password.js +1 -1
  55. package/waibuMpa/route/{my-stuff → your-stuff}/profile/edit.js +2 -2
  56. package/waibuMpa/route/{my-stuff → your-stuff}/profile.js +1 -1
  57. package/waibuMpa/route/{my-stuff → your-stuff}/reset-api-key.js +2 -2
  58. package/bajo/hook/waibu-socket-io@on-server-connect.js +0 -5
  59. package/bajoTemplate/layout/wide.html +0 -15
  60. package/bajoTemplate/template/my-stuff/change-password.html +0 -4
  61. package/bajoTemplate/template/my-stuff/profile/edit.html +0 -6
  62. package/bajoTemplate/template/my-stuff/profile/view.html +0 -6
  63. package/bajoTemplate/template/my-stuff/reset-api-key.html +0 -4
  64. package/lib/check-site-id.js +0 -57
  65. /package/bajoTemplate/partial/{my-stuff → your-stuff}/reset-api-key.html +0 -0
@@ -2,8 +2,8 @@ async function afterBuildLocals (locals, req) {
2
2
  const { routePath } = this.app.waibu
3
3
  const items = []
4
4
  if (req.user) {
5
- items.push({ icon: 'person', 't:tooltip': 'yourProfile', href: routePath('sumba:/my-stuff/profile') })
6
- items.push({ icon: 'key', 't:tooltip': 'changePassword', href: routePath('sumba:/my-stuff/change-password') })
5
+ items.push({ icon: 'person', 't:tooltip': 'yourProfile', href: routePath('sumba:/your-stuff/profile') })
6
+ items.push({ icon: 'key', 't:tooltip': 'changePassword', href: routePath('sumba:/your-stuff/change-password') })
7
7
  items.push({ component: 'navItemSignout', 't:tooltip': 'signout', bottom: true })
8
8
  } else {
9
9
  items.push({ icon: 'signin', 't:tooltip': 'signin', href: routePath('sumba:/signin') })
@@ -1,9 +1,8 @@
1
- import checkSiteId from '../../lib/check-site-id.js'
2
-
3
1
  const onRequest = {
4
2
  level: 10,
5
3
  handler: async function (req, reply) {
6
- await checkSiteId.call(this, req, reply)
4
+ const hostname = req.hostname.split(':')[0]
5
+ req.site = await this.getSite(hostname)
7
6
  }
8
7
  }
9
8
 
@@ -50,9 +50,9 @@
50
50
  "personInCharge": "Person In Charge",
51
51
  "contactForm": "Contact Form",
52
52
  "terms": "Terms",
53
- "cookie": "Cookie Policy",
53
+ "cookie": "Cookie",
54
54
  "cookiePolicy": "Cookie Policy",
55
- "privacy": "Privacy Statement",
55
+ "privacy": "Privacy",
56
56
  "termsConditions": "Terms and Conditions",
57
57
  "privacyStatement": "Privacy Statement",
58
58
  "legalInfo": "Legal Info",
@@ -88,6 +88,8 @@
88
88
  "catMisc": "Misc",
89
89
  "catTechnical": "Technical Problem",
90
90
  "activation": "Activation",
91
+ "addTroubleTickets": "Create New Ticket",
92
+ "ourAddress": "Our Address",
91
93
  "field": {
92
94
  "currentPassword": "Current Password",
93
95
  "newPassword": "New Password",
package/bajo/intl/id.json CHANGED
@@ -89,6 +89,8 @@
89
89
  "catMisc": "Lain-lain",
90
90
  "catTechnical": "Masalah Teknis",
91
91
  "activation": "Aktivasi",
92
+ "addTroubleTickets": "Buat Ticket Baru",
93
+ "ourAddress": "Alamat Kami",
92
94
  "field": {
93
95
  "currentPassword": "Kata Sandi Saat Ini",
94
96
  "newPassword": "Kata Sandi Baru",
@@ -0,0 +1,15 @@
1
+ <c:page-start />
2
+ <c:container>
3
+ <c:div flex="align-items:center justify-content:center" dim="height:viewport">
4
+ <c:grid-row dim="width:100">
5
+ <c:grid-col col="4-lg 3-md"></c:grid-col>
6
+ <c:grid-col col="4-lg 6-md">
7
+ <c:app-launcher trigger />
8
+ <c:heading margin="bottom-4" text="align:center" type="3-display" content="<%= page.title %>" />
9
+ <!-- body -->
10
+ <!-- include sumba.partial:/layout/footer.html -->
11
+ </c:grid-col>
12
+ <c:grid-col col="4-lg 3-md"></c:grid-col>
13
+ </c:grid-row>
14
+ </c:container>
15
+ <c:page-end />
@@ -1,14 +1,15 @@
1
1
  <c:page-start />
2
- <c:container flex="align-items:center" dim="height:viewport">
3
- <c:grid-row dim="width:100">
4
- <c:grid-col col="4-md"></c:grid-col>
5
- <c:grid-col col="4-md">
6
- <c:app-launcher trigger />
7
- <c:heading margin="bottom-4" text="align:center" type="3-display" content="<%= page.title %>" />
8
- <!-- body -->
9
- <!-- include sumba.partial:/layout/footer.html -->
10
- </c:grid-col>
11
- <c:grid-col col="4-md"></c:grid-col>
12
- </c:grid-row>
13
- </c:container>
14
- <c:page-end />
2
+ <c:main flex>
3
+ <!-- include sumba.partial:/layout/sidebar.html -->
4
+ <c:div flex="fill column">
5
+ <!-- include sumba.partial:/layout/navbar.html -->
6
+ <!-- include sumba.partial:/layout/breadcrumb.html -->
7
+ <c:container margin="start-0 bottom-5" padding="x-3">
8
+ <c:div style="max-width: 992px;">
9
+ <!-- body -->
10
+ <!-- include sumba.partial:/layout/footer.html -->
11
+ </c:div>
12
+ </c:container>
13
+ </c:div>
14
+ </c:main>
15
+ <c:page-end back-to-top/>
@@ -2,7 +2,7 @@
2
2
  <c:modal-body>
3
3
  <pre><code id="api-key"><%= form.token %></code></pre>
4
4
  <c:div flex="justify-content:between align-items:center" margin="top-3">
5
- <c:a icon="arrowsRepeat" href="sumba:/my-stuff/reset-api-key" t:content="reset" />
5
+ <c:a icon="arrowsRepeat" href="sumba:/your-stuff/reset-api-key" t:content="reset" />
6
6
  <div>
7
7
  <c:btn color="primary" x-data @click="await wbs.copyToClipboard('#api-key', true)" t:content="copyClipboard" />
8
8
  <c:btn margin="start-1" color="secondary" dismiss t:content="close" />
@@ -1,12 +1,20 @@
1
- <c:form button reset-validation referer grid-gutter="2">
2
- <c:form-input name="firstName" col="6-lg" label-floating <%= _meta.user ? 'readonly' : '' %> />
3
- <c:form-input name="lastName" col="6-lg" label-floating <%= _meta.user ? 'readonly' : '' %> />
4
- <c:form-input type="email" col="6-lg" name="email" label-floating <%= _meta.user ? 'readonly' : '' %> />
5
- <c:form-select name="cat" col="6-lg" label-floating>
6
- <% for (const cat of cats) { %>
7
- <c:option value="<%= cat.name %>" t:content="<%= _.camelCase('cat ' + cat.name) %>" />
8
- <% } %>
9
- </c:form-select>
10
- <c:form-input name="subject" label-floating />
11
- <c:form-textarea name="message" label-floating style="height:10em"/>
12
- </c:form>
1
+ <c:grid-row>
2
+ <c:grid-col col="8-md">
3
+ <c:form button reset-validation referer grid-gutter="2">
4
+ <c:form-input name="firstName" col="6-lg" label-floating <%= _meta.user ? 'readonly' : '' %> />
5
+ <c:form-input name="lastName" col="6-lg" label-floating <%= _meta.user ? 'readonly' : '' %> />
6
+ <c:form-input type="email" col="6-lg" name="email" label-floating <%= _meta.user ? 'readonly' : '' %> />
7
+ <c:form-select name="cat" col="6-lg" label-floating>
8
+ <% for (const cat of cats) { %>
9
+ <c:option value="<%= cat.name %>" t:content="<%= _.camelCase('cat ' + cat.name) %>" />
10
+ <% } %>
11
+ </c:form-select>
12
+ <c:form-input name="subject" label-floating />
13
+ <c:form-textarea name="message" label-floating style="height:10em"/>
14
+ </c:form>
15
+ </c:grid-col>
16
+ <c:grid-col col="4-md">
17
+ <c:heading t:content="ourAddress" type="6-display" />
18
+ <!-- include waibuMpa.partial:/address.html -->
19
+ </c:grid-col>
20
+ </c:grid-row>
@@ -1,17 +1,16 @@
1
1
  <c:footer margin="top-5">
2
+ <c:div id="footer">test</c:div>
2
3
  <small>
3
- <c:nav flex="justify-content:center">
4
- <c:nav-item href="/" icon-end="house"/>
5
- <c:nav-item t:content="cookie" href="sumba:/info/cookie-policy"/>
6
- <c:nav-item t:content="privacy" href="sumba:/info/privacy"/>
7
- <c:nav-item t:content="terms" href="sumba:/info/terms-conditions"/>
8
- </c:nav>
4
+ <c:nav flex="justify-content:center" tag="ul">
9
5
  <% if (!(_meta.routeOpts.pathSrc.startsWith('/my-profile') || _meta.routeOpts.pathSrc.startsWith('/info') ||
10
6
  _meta.routeOpts.pathSrc.startsWith('/help'))) { %>
11
- <c:nav flex="justify-content:center">
12
- <c:nav-dropdown-darkmode />
13
- <c:nav-dropdown-language />
14
- </c:nav>
7
+ <c:nav-dropdown-darkmode padding="x-2"/>
8
+ <c:nav-dropdown-language padding="x-2"/>
9
+ <c:nav-divider />
15
10
  <% } %>
11
+ <c:nav-item t:content="cookie" href="sumba:/info/cookie-policy" padding="x-1"/>
12
+ <c:nav-item t:content="privacy" href="sumba:/info/privacy" padding="x-1"/>
13
+ <c:nav-item t:content="terms" href="sumba:/info/terms-conditions" padding="x-2"/>
14
+ </c:nav>
16
15
  </small>
17
16
  </c:footer>
@@ -1 +1 @@
1
- <c:list-item t:content="Change Password" href="sumba:/my-stuff/change-password" icon="key"/>
1
+ <c:nav-item t:content="changePassword" href="sumba:/your-stuff/change-password"/>
@@ -1 +1 @@
1
- <c:list-item t:content="Forgot Password" href="sumba:/user/forgot-password" icon="key"/>
1
+ <c:nav-item t:content="forgotPassword" href="sumba:/user/forgot-password"/>
@@ -1 +1 @@
1
- <c:list-item href="/" t:content="Goto Home" icon="house" />
1
+ <c:nav-item href="/" t:content="gotoHome" />
@@ -1,14 +1,14 @@
1
1
  <% if (_meta.user) { %>
2
- <c:list-item href="sumba:/my-stuff/profile" t:content="yourProfile" />
3
- <c:list-item href="sumba:/my-stuff/change-password" t:content="changePassword" />
2
+ <c:nav-item href="sumba:/your-stuff/profile" t:content="yourProfile" />
3
+ <c:nav-item href="sumba:/your-stuff/change-password" t:content="changePassword" />
4
4
  <% if (attr.withSignout) { %>
5
- <c:list-item href="sumba:/signout" t:content="signout" />
5
+ <c:nav-item href="sumba:/signout" t:content="signout" />
6
6
  <% } %>
7
7
  <% } else { %>
8
- <c:list-item href="sumba:/signin" t:content="signin" />
9
- <c:list-item href="sumba:/user/signup" t:content="signup" />
10
- <c:list-item href="sumba:/user/forgot-password" t:content="forgotPassword" />
8
+ <c:nav-item href="sumba:/signin" t:content="signin" />
9
+ <c:nav-item href="sumba:/user/signup" t:content="signup" />
10
+ <c:nav-item href="sumba:/user/forgot-password" t:content="forgotPassword" />
11
11
  <% if (_hasPlugin('masohi') && _hasPlugin('masohiMail')) { %>
12
- <c:list-item href="sumba:/user/activation" t:content="userActivation" />
12
+ <c:nav-item href="sumba:/user/activation" t:content="userActivation" />
13
13
  <% } %>
14
14
  <% } %>
@@ -1 +1 @@
1
- <c:list-item t:content="Signin" href="sumba:/signin" icon="signin"/>
1
+ <c:nav-item t:content="signin" href="sumba:/signin" />
@@ -1 +1 @@
1
- <c:list-item t:content="Signout" href="sumba:/signout" icon="signout"/>
1
+ <c:nav-item t:content="signout" href="sumba:/signout" />
@@ -1 +1 @@
1
- <c:list-item t:content="New User Signup" href="sumba:/user/signup" icon="personAdd"/>
1
+ <c:nav-item t:content="newUserSignup" href="sumba:/user/signup" />
@@ -1 +1 @@
1
- <c:list-item t:content="yourProfile" href="sumba:/my-stuff/profile" icon="person"/>
1
+ <c:nav-item t:content="yourProfile" href="sumba:/your-stuff/profile" />
@@ -3,9 +3,11 @@
3
3
  <c:form-password name="password" label-floating wrapper-margin="bottom-3" />
4
4
  </c:form>
5
5
  <% if (!page.noLinks) { %>
6
- <c:list type="unstyled" margin="start-3">
7
- <!-- include sumba.partial:/list-item/forgot-password.html -->
8
- <!-- include sumba.partial:/list-item/user-signup.html -->
9
- <!-- include sumba.partial:/list-item/goto-home.html -->
10
- </c:list>
6
+ <c:div move-to="#footer" flex="justify-content:center">
7
+ <c:nav type="inline">
8
+ <!-- include sumba.partial:/list-item/forgot-password.html -->
9
+ <!-- include sumba.partial:/list-item/user-signup.html -->
10
+ <!-- include sumba.partial:/list-item/goto-home.html -->
11
+ </c:nav>
12
+ </c:div>
11
13
  <% } %>
@@ -1,7 +1,11 @@
1
1
  <c:p t:content="signoutWarning" />
2
2
  <c:form method="POST" action="sumba:/signout" referer>
3
3
  <c:btn color="primary" t:content="signoutNow" type="submit" />
4
- <% if (!page.noLinks) { %>
5
- <c:btn color="link" icon="house" t:content="gotoHome" href="/" />
6
- <% } %>
7
4
  </c:form>
5
+ <% if (!page.noLinks) { %>
6
+ <c:div move-to="#footer" flex="justify-content:center">
7
+ <c:nav type="inline">
8
+ <!-- include sumba.partial:/list-item/goto-home.html -->
9
+ </c:nav>
10
+ </c:div>
11
+ <% } %>
@@ -2,9 +2,11 @@
2
2
  <c:form-input name="key" label-floating />
3
3
  </c:form>
4
4
  <% if (!page.noLinks) { %>
5
- <c:list type="unstyled" margin="start-3">
5
+ <c:div move-to="#footer" flex="justify-content:center">
6
+ <c:nav type="inline">
6
7
  <!-- include sumba.partial:/list-item/signin.html -->
7
8
  <!-- include sumba.partial:/list-item/forgot-password.html -->
8
9
  <!-- include sumba.partial:/list-item/goto-home.html -->
9
- </c:list>
10
+ </c:nav>
11
+ </c:div>
10
12
  <% } %>
@@ -6,9 +6,11 @@
6
6
  <!-- include sumba.partial:/user/forgot-password-nomail.md -->
7
7
  <% } %>
8
8
  <% if (!page.noLinks) { %>
9
- <c:list type="unstyled" margin="start-3">
9
+ <c:div move-to="#footer" flex="justify-content:center">
10
+ <c:nav type="inline">
10
11
  <!-- include sumba.partial:/list-item/signin.html -->
11
12
  <!-- include sumba.partial:/list-item/user-signup.html -->
12
13
  <!-- include sumba.partial:/list-item/goto-home.html -->
13
- </c:list>
14
+ </c:nav>
15
+ </c:div>
14
16
  <% } %>
@@ -8,9 +8,11 @@
8
8
  <c:form-check name="agree" col="12" value="true" t:label="agreeToTerm%s%s|<%= _routePath('sumba:/info/terms-conditions') %>|termsConditions" />
9
9
  </c:form>
10
10
  <% if (!page.noLinks) { %>
11
- <c:list type="unstyled" margin="start-3">
11
+ <c:div move-to="#footer" flex="justify-content:center">
12
+ <c:nav type="inline">
12
13
  <!-- include sumba.partial:/list-item/forgot-password.html -->
13
14
  <!-- include sumba.partial:/list-item/signin.html -->
14
15
  <!-- include sumba.partial:/list-item/goto-home.html -->
15
- </c:list>
16
+ </c:nav>
17
+ </c:div>
16
18
  <% } %>
@@ -4,7 +4,9 @@
4
4
  <!-- include sumba.partial:/user/signup/success-nomail.md -->
5
5
  <% } %>
6
6
  <% if (!page.noLinks) { %>
7
- <c:list type="unstyled" margin="start-3">
8
- <c:list-item t:content="gotoHome" href="/" icon="house"/>
9
- </c:list>
7
+ <c:div move-to="#footer" flex="justify-content:center">
8
+ <c:nav type="inline">
9
+ <c:nav-item t:content="gotoHome" href="/" icon="house"/>
10
+ </c:nav>
11
+ </c:div>
10
12
  <% } %>
@@ -1,12 +1,12 @@
1
1
  <c:grid-row>
2
- <c:grid-col col="6-md">
2
+ <c:grid-col col="5-md">
3
3
  <c:form button reset-validation referer>
4
4
  <c:form-password name="currentPassword" label-floating wrapper-margin="bottom-2" />
5
5
  <c:form-password name="newPassword" label-floating wrapper-margin="bottom-2" />
6
6
  <c:form-password name="verifyNewPassword" label-floating wrapper-margin="bottom-3" />
7
7
  </c:form>
8
8
  </c:grid-col>
9
- <c:grid-col col="6-md">
9
+ <c:grid-col col="7-md">
10
10
 
11
11
  </c:grid-col>
12
12
  </c:grid-row>
@@ -40,11 +40,11 @@
40
40
  <hr />
41
41
  <c:heading type="5" t:content="more" margin="top-3" />
42
42
  <c:list type="group" hover>
43
- <c:list-item href="sumba:/my-stuff/change-password" t:content="changePassword" />
43
+ <c:list-item href="sumba:/your-stuff/change-password" t:content="changePassword" />
44
44
  <c:list-item t:content="displayApiKey" target="api-key-modal"/>
45
45
  </c:list>
46
46
  <c:list type="unstyled" margin="top-3">
47
- <c:list-item href="sumba:/my-stuff/profile" t:content="backToProfile" icon="arrowStart" />
47
+ <c:list-item href="sumba:/your-stuff/profile" t:content="backToProfile" icon="arrowStart" />
48
48
  </c:list>
49
49
  <!-- include sumba.partial:/api-key-modal.html -->
50
50
  </c:grid-col>
@@ -28,7 +28,7 @@
28
28
  </c:div>
29
29
  <c:heading type="5" t:content="more" margin="top-3" />
30
30
  <c:list type="group" hover>
31
- <c:list-item href="sumba:/my-stuff/profile/edit" t:content="updateProfile" />
31
+ <c:list-item href="sumba:/your-stuff/profile/edit" t:content="updateProfile" />
32
32
  <c:list-item t:content="displayApiKey" target="api-key-modal"/>
33
33
  </c:list>
34
34
  <!-- include sumba.partial:/api-key-modal.html -->
@@ -1,4 +1,3 @@
1
1
  ---
2
2
  t:title: contactForm
3
- layout: sumba.layout:/wide.html
4
3
  ---
@@ -1,4 +1,3 @@
1
1
  ---
2
2
  t:title: contactForm
3
- layout: sumba.layout:/wide.html
4
3
  ---
@@ -1,4 +1,3 @@
1
1
  ---
2
2
  t:title: addTroubleTickets
3
- layout: sumba.layout:/wide.html
4
3
  ---
@@ -1,4 +1,3 @@
1
1
  ---
2
2
  t:title: troubleTicketsDetails
3
- layout: sumba.layout:/wide.html
4
3
  ---
@@ -1,4 +1,3 @@
1
1
  ---
2
2
  t:title: troubleTickets
3
- layout: sumba.layout:/wide.html
4
3
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: signin
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: signout
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: userActivation
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: forgotPassword
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: forgotPassword
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: forgotPassword
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: newUserSignup
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  t:title: newUserSignup
3
+ layout: sumba.layout:/centered.html
3
4
  ---
@@ -0,0 +1,3 @@
1
+ ---
2
+ t:title: changePassword
3
+ ---
@@ -0,0 +1,3 @@
1
+ ---
2
+ t:title: editYourProfile
3
+ ---
@@ -0,0 +1,3 @@
1
+ ---
2
+ t:title: yourProfile
3
+ ---
@@ -0,0 +1,3 @@
1
+ ---
2
+ t:title: resetApiKey
3
+ ---
@@ -3,7 +3,7 @@ async function checkIconset (req, reply) {
3
3
  const mpa = this.app.waibuMpa
4
4
 
5
5
  if (!req.site) return
6
- if (mpa.iconsets.length === 1) req.iconset = mpa.iconsets[0]
6
+ if (mpa.iconsets.length === 1) req.iconset = mpa.iconsets[0].name
7
7
  else {
8
8
  const siteIconset = get(req, 'site.setting.waibuMpa.iconset')
9
9
  req.iconset = get(mpa, 'config.iconset.default', siteIconset)
package/lib/check-team.js CHANGED
@@ -1,22 +1,9 @@
1
1
  import { pathsToCheck } from './check-user-id.js'
2
2
 
3
- async function mergeTeam (req) {
4
- const { map, pick } = this.lib._
5
- const { recordFindAll } = this.app.dobo
6
- req.user.teams = []
7
- const query = { userId: req.user.id, siteId: req.site.id }
8
- const userTeam = await recordFindAll('SumbaTeamUser', { query })
9
- if (userTeam.length === 0) return
10
- delete query.userId
11
- query.id = { $in: map(userTeam, 'id'), status: 'ENABLED' }
12
- const team = await recordFindAll('SumbaTeam', { query })
13
- if (team.length > 0) req.user.teams.push(...map(team, t => pick(t, ['id', 'alias'])))
14
- }
15
-
16
3
  async function checkTeam (req, reply, source) {
17
4
  if (!req.user) return
18
5
  const { map } = this.lib._
19
- await mergeTeam.call(this, req)
6
+ await this.mergeTeam(req.user, req.site)
20
7
  const paths = pathsToCheck.call(this, req, true)
21
8
  const teams = map(req.user.teams, 'alias')
22
9
  const match = this.checkPathsByTeam({ paths, method: req.method, teams, guards: this.teamRoutes })
@@ -3,11 +3,11 @@ async function checkTheme (req, reply) {
3
3
  const mpa = this.app.waibuMpa
4
4
 
5
5
  if (!req.site) return
6
- if (mpa.themes.length === 1) req.theme = mpa.themes[0]
6
+ if (mpa.themes.length === 1) req.theme = mpa.themes[0].name
7
7
  else {
8
8
  const siteTheme = get(req, 'site.setting.waibuMpa.theme')
9
9
  req.theme = get(mpa, 'config.theme.set', siteTheme)
10
- req.theme = req.theme ?? mpa.themes[0]
10
+ req.theme = req.theme ?? mpa.themes[0].name
11
11
  }
12
12
  }
13
13
 
@@ -13,24 +13,22 @@ export function pathsToCheck (req, withHome) {
13
13
 
14
14
  async function setUser (req) {
15
15
  const { get } = this.lib._
16
- const id = get(req, 'session.user.id')
16
+ const id = get(req, 'session.userId')
17
17
  if (!id) return
18
18
  try {
19
19
  const user = await this.getUser(id)
20
20
  if (user) req.user = user
21
- else req.session.user = null
21
+ else req.session.userId = null
22
22
  } catch (err) {
23
- req.session.user = null
23
+ req.session.userId = null
24
24
  }
25
25
  }
26
26
 
27
- async function mergeSetting (req) {
28
- req.user.setting = {}
29
- }
30
-
31
27
  async function checkUserId (req, reply, source) {
32
28
  const { merge, isEmpty, camelCase, get } = this.lib._
33
29
  const { routePath } = this.app.waibu
30
+ const userId = get(req, 'session.userId')
31
+ if (req.session) req.session.siteId = req.site.id
34
32
 
35
33
  const webApp = get(req, 'routeOptions.config.webApp', 'waibu')
36
34
  if (!req.routeOptions.url) {
@@ -51,17 +49,16 @@ async function checkUserId (req, reply, source) {
51
49
  if (neg) anonymousPath = undefined
52
50
  }
53
51
  if (!securePath && !anonymousPath) {
54
- if (req.session && req.session.user) await setUser.call(this, req)
52
+ if (userId) await setUser.call(this, req)
55
53
  return
56
54
  }
57
55
  if (anonymousPath) {
58
- if (!req.session) return // can't check, so don't care
59
- if (!req.session.user) return // not authenticated, why bother
56
+ if (!userId) return
60
57
  req.session.ref = req.url
61
58
  return reply.redirectTo(routePath(this.config.redirect.signout))
62
59
  }
63
60
  if (securePath) {
64
- if (req.session && req.session.user) {
61
+ if (userId) {
65
62
  await setUser.call(this, req)
66
63
  return
67
64
  }
@@ -80,7 +77,6 @@ async function checkUserId (req, reply, source) {
80
77
  }
81
78
  }
82
79
  if (!success) throw this.error('accessDeniedNoAuth', merge({ statusCode: 403 }, payload))
83
- await mergeSetting.call(this, req)
84
80
  }
85
81
  }
86
82
 
@@ -0,0 +1,25 @@
1
+ const auth = {
2
+ level: 5,
3
+ handler: async function (socket) {
4
+ const { camelCase } = this.lib._
5
+ const { req } = socket
6
+ const { session } = req
7
+ const site = await this.getSite(session.siteId)
8
+ socket.join(camelCase(`site ${site.alias}`))
9
+ let user
10
+ if (session.userId) {
11
+ user = await this.getUser(session.userId)
12
+ if (user) {
13
+ socket.join(camelCase(`user ${user.username}`))
14
+ await this.mergeTeam(user, site)
15
+ for (const team of user.teams) {
16
+ socket.join(camelCase(`team ${team.alias}`))
17
+ }
18
+ }
19
+ }
20
+ socket.req.site = site
21
+ socket.req.user = user
22
+ }
23
+ }
24
+
25
+ export default auth
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sumba",
3
- "version": "1.1.12",
3
+ "version": "1.1.13",
4
4
  "description": "Bajo Framework's Biz Suite",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/plugin/factory.js CHANGED
@@ -28,7 +28,7 @@ async function factory (pkgName) {
28
28
  constructor () {
29
29
  super(pkgName, me.app)
30
30
  this.alias = 'sumba'
31
- this.dependencies = ['bajo-extra', 'bajo-common-db']
31
+ this.dependencies = ['bajo-extra', 'bajo-common-db', 'bajo-config']
32
32
  this.config = {
33
33
  multiSite: false,
34
34
  waibu: {
@@ -36,17 +36,45 @@ async function factory (pkgName) {
36
36
  prefix: 'site'
37
37
  },
38
38
  waibuMpa: {
39
- home: 'sumba:/my-stuff/profile',
39
+ home: 'sumba:/your-stuff/profile',
40
40
  icon: 'globe',
41
41
  redirect: {
42
- '/': 'sumba:/my-stuff/profile',
43
- '/my-stuff': 'sumba:/my-stuff/profile',
42
+ '/': 'sumba:/your-stuff/profile',
43
+ '/your-stuff': 'sumba:/your-stuff/profile',
44
44
  '/info': 'sumba:/info/about-us',
45
- '/user': 'sumba:/my-stuff/profile',
45
+ '/user': 'sumba:/your-stuff/profile',
46
46
  '/db/export': 'sumba:/db/export/list',
47
47
  '/help': 'sumba:/help/contact-form',
48
48
  '/help/trouble-tickets': 'sumba:/help/trouble-tickets/list'
49
- }
49
+ },
50
+ pages: [{
51
+ title: 'account',
52
+ level: 80,
53
+ children: [
54
+ // anonymous only
55
+ { title: 'signin', href: 'sumba:/signin', visible: 'anon' },
56
+ { title: 'forgotPassword', href: 'sumba:/forgot-password', visible: 'anon' },
57
+ { title: 'newUserSignup', href: 'sumba:/user/signup', visible: 'anon' },
58
+ { title: '-', visible: 'anon' },
59
+ { title: 'activation', href: 'sumba:/user/activation', visible: 'anon' },
60
+ // authenticated only
61
+ { title: 'yourProfile', href: 'sumba:/your-stuff/profile', visible: 'auth' },
62
+ { title: 'changePassword', href: 'sumba:/your-stuff/change-password', visible: 'auth' },
63
+ { title: '-', visible: 'auth' },
64
+ { title: 'signout', href: 'sumba:/signout', visible: 'auth' }
65
+ ]
66
+ }, {
67
+ title: 'help',
68
+ level: 90,
69
+ children: [
70
+ { title: 'contactForm', href: 'sumba:/help/contact-form' },
71
+ { title: 'troubleTickets', href: 'sumba:/help/trouble-tickets' },
72
+ { title: '-', visible: 'auth' },
73
+ { title: 'cookiePolicy', href: 'sumba:/info/cookie-policy' },
74
+ { title: 'privacy', href: 'sumba:/info/privacy' },
75
+ { title: 'termsConditions', href: 'sumba:/info/terms-conditions' }
76
+ ]
77
+ }]
50
78
  },
51
79
  waibuAdmin: {
52
80
  modelDisabled: 'all'
@@ -126,13 +154,26 @@ async function factory (pkgName) {
126
154
  getUser = async (rec, safe = true) => {
127
155
  const { recordGet } = this.app.dobo
128
156
  const { omit, isPlainObject } = this.lib._
129
-
130
157
  let user
131
158
  if (isPlainObject(rec)) user = rec
132
159
  else user = await recordGet('SumbaUser', rec, { noHook: true })
133
160
  return safe ? omit(user, this.unsafeUserFields) : user
134
161
  }
135
162
 
163
+ mergeTeam = async (user, site) => {
164
+ if (!user) return
165
+ const { map, pick } = this.lib._
166
+ const { recordFindAll } = this.app.dobo
167
+ user.teams = []
168
+ const query = { userId: user.id, siteId: site.id }
169
+ const userTeam = await recordFindAll('SumbaTeamUser', { query })
170
+ if (userTeam.length === 0) return
171
+ delete query.userId
172
+ query.id = { $in: map(userTeam, 'id'), status: 'ENABLED' }
173
+ const team = await recordFindAll('SumbaTeam', { query })
174
+ if (team.length > 0) user.teams.push(...map(team, t => pick(t, ['id', 'alias'])))
175
+ }
176
+
136
177
  getUserFromUsernamePassword = async (username = '', password = '', req) => {
137
178
  const { importPkg } = this.app.bajo
138
179
  const { recordFind, validate } = this.app.dobo
@@ -174,8 +215,8 @@ async function factory (pkgName) {
174
215
  const { routePath } = this.app.waibu
175
216
 
176
217
  if (!req.session) return false
177
- if (req.session.user) {
178
- req.user = await getUser(req.session.user.id)
218
+ if (req.session.userId) {
219
+ req.user = await getUser(req.session.userId)
179
220
  return true
180
221
  }
181
222
  const redir = routePath(this.config.redirect.signin, req)
@@ -312,6 +353,68 @@ async function factory (pkgName) {
312
353
  }
313
354
  return guarded
314
355
  }
356
+
357
+ getSite = async (hostname, useId) => {
358
+ const { omit } = this.lib._
359
+ const { recordFind } = this.app.dobo
360
+ const omitted = ['status']
361
+
362
+ const mergeSetting = async (site) => {
363
+ const { defaultsDeep, parseObject } = this.app.bajo
364
+ const { trim, get, filter } = this.lib._
365
+ const { recordFind, recordGet } = this.app.dobo
366
+ const defSetting = {}
367
+ const nsSetting = {}
368
+ const query = {
369
+ ns: { $in: this.app.bajo.pluginNames },
370
+ siteId: site.id
371
+ }
372
+ const all = await recordFind('SumbaSiteSetting', { query, limit: -1 })
373
+ for (const ns of this.app.bajo.pluginNames) {
374
+ nsSetting[ns] = {}
375
+ defSetting[ns] = get(this, `app.${ns}.config.siteSetting`, {})
376
+ const items = filter(all, { ns })
377
+ for (const item of items) {
378
+ let value = trim([item.value] ?? '')
379
+ if (['[', '{'].includes(value[0])) value = JSON.parse(value)
380
+ else if (Number(value)) value = Number(value)
381
+ else if (['true', 'false'].includes(value)) value = value === 'true'
382
+ nsSetting[ns][item.key] = value
383
+ }
384
+ }
385
+ site.setting = parseObject(defaultsDeep({}, nsSetting, defSetting))
386
+ // additional fields
387
+ const country = await recordGet('CdbCountry', site.country, { noHook: true })
388
+ site.countryName = (country ?? {}).name ?? site.country
389
+ }
390
+
391
+ let site = {}
392
+
393
+ if (!this.config.multiSite) {
394
+ const resp = await recordFind('SumbaSite', { query: { alias: 'default' } }, { noHook: true })
395
+ site = omit(resp[0], omitted)
396
+ await mergeSetting(site)
397
+ return site
398
+ }
399
+ let query
400
+ if (useId) query = { id: hostname }
401
+ else {
402
+ query = {
403
+ $or: [
404
+ { hostname },
405
+ { alias: hostname }
406
+ ]
407
+ }
408
+ }
409
+ const filter = { query, limit: 1 }
410
+ const rows = await recordFind('SumbaSite', filter, { noHook: true })
411
+ if (rows.length === 0) throw this.error('unknownSite')
412
+ const row = omit(rows[0], omitted)
413
+ if (row.status !== 'ACTIVE') throw this.error('siteInactiveInfo')
414
+ site = row
415
+ await mergeSetting(site)
416
+ return site
417
+ }
315
418
  }
316
419
  }
317
420
 
@@ -1,11 +1,11 @@
1
1
  [
2
- "/my-stuff/**/*",
2
+ "/your-stuff/**/*",
3
3
  "/signout",
4
4
  "/help/trouble-tickets/**/*",
5
5
  {
6
6
  "path": "/user/api-key",
7
7
  "routeHandler": "restapi"
8
8
  }, {
9
- "path": "/my-stuff/**/*",
9
+ "path": "/your-stuff/**/*",
10
10
  "routeHandler": "restapi"
11
11
  }]
@@ -13,7 +13,7 @@ const signin = {
13
13
  if (req.method === 'POST') {
14
14
  try {
15
15
  const user = omit(await getUserFromUsernamePassword(username, password, req), ['password', 'token'])
16
- req.session.user = user
16
+ req.session.userId = user.id
17
17
  const sid = await getSessionId(req.headers.cookie)
18
18
  if (this.bajoEmitter) await this.app.bajoEmitter.emit(`${this.name}.signin`, user, sid)
19
19
  await runHook(`${this.name}:afterSignin`, user, sid, req)
@@ -10,10 +10,8 @@ const signout = {
10
10
  req.session.ref = null
11
11
  if (req.method === 'POST') {
12
12
  const sid = await getSessionId(req.headers.cookie)
13
- const user = req.session.user
14
- req.session.user = null
15
- if (this.bajoEmitter) await this.app.bajoEmitter.emit(`${this.name}.signout`, user, sid)
16
- await runHook(`${this.name}:afterSignout`, user, sid, req)
13
+ req.session.userId = null
14
+ await runHook(`${this.name}:afterSignout`, sid, req)
17
15
  const { query, params } = req
18
16
  // const url = !isEmpty(referer) ? referer : this.config.redirect.home
19
17
  const url = this.config.redirect.afterSignout
@@ -35,7 +35,7 @@ const profile = {
35
35
  error = err
36
36
  }
37
37
  }
38
- return reply.view('sumba.template:/my-stuff/change-password.html', { form, error })
38
+ return reply.view('sumba.template:/your-stuff/change-password.html', { form, error })
39
39
  }
40
40
  }
41
41
 
@@ -17,12 +17,12 @@ const profile = {
17
17
  const resp = await recordUpdate({ req, reply, model: 'SumbaUser', id: req.user.id, body, options })
18
18
  form = resp.data
19
19
  req.flash('notify', req.t('profileUpdated'))
20
- return reply.redirectTo('sumba:/my-stuff/profile')
20
+ return reply.redirectTo('sumba:/your-stuff/profile')
21
21
  } catch (err) {
22
22
  error = err
23
23
  }
24
24
  }
25
- return reply.view('sumba.template:/my-stuff/profile/edit.html', { form, error })
25
+ return reply.view('sumba.template:/your-stuff/profile/edit.html', { form, error })
26
26
  }
27
27
  }
28
28
 
@@ -7,7 +7,7 @@ const profile = {
7
7
  const resp = await recordGet({ model: 'SumbaUser', req, id: req.user.id, options })
8
8
  const form = resp.data
9
9
  form.token = await hash(form.salt)
10
- return reply.view('sumba.template:/my-stuff/profile/view.html', { form })
10
+ return reply.view('sumba.template:/your-stuff/profile/view.html', { form })
11
11
  }
12
12
  }
13
13
 
@@ -27,12 +27,12 @@ const resetApiKey = {
27
27
  await recordUpdate(model, req.user.id, { salt: generateId() }, { req, reply, noFlash: true })
28
28
  await delay(2000) // ensure req.user cache is expired
29
29
  req.flash('notify', req.t('resetApiKeySuccessfull'))
30
- return reply.redirectTo('sumba:/my-stuff/profile')
30
+ return reply.redirectTo('sumba:/your-stuff/profile')
31
31
  } catch (err) {
32
32
  error = err
33
33
  }
34
34
  }
35
- return reply.view('sumba.template:/my-stuff/reset-api-key.html', { form, error })
35
+ return reply.view('sumba.template:/your-stuff/reset-api-key.html', { form, error })
36
36
  }
37
37
  }
38
38
 
@@ -1,5 +0,0 @@
1
- async function onServerConnect (socket) {
2
- socket.emit('session', socket.session)
3
- }
4
-
5
- export default onServerConnect
@@ -1,15 +0,0 @@
1
- <c:page-start />
2
- <c:main flex>
3
- <!-- include sumba.partial:/layout/sidebar.html -->
4
- <c:div flex="fill column">
5
- <!-- include sumba.partial:/layout/navbar.html -->
6
- <!-- include sumba.partial:/layout/breadcrumb.html -->
7
- <c:container margin="start-0 bottom-5" padding="x-3">
8
- <c:div style="max-width: 992px;">
9
- <!-- body -->
10
- <!-- include sumba.partial:/layout/footer.html -->
11
- </c:div>
12
- </c:container>
13
- </c:div>
14
- </c:main>
15
- <c:page-end back-to-top/>
@@ -1,4 +0,0 @@
1
- ---
2
- t:title: changePassword
3
- layout: sumba.layout:/wide.html
4
- ---
@@ -1,6 +0,0 @@
1
- ---
2
- t:title: editYourProfile
3
- layout: sumba.layout:/wide.html
4
- scripts:
5
- - waibuExtra.virtual:/holderjs/holder.min.js
6
- ---
@@ -1,6 +0,0 @@
1
- ---
2
- t:title: yourProfile
3
- layout: sumba.layout:/wide.html
4
- scripts:
5
- - waibuExtra.virtual:/holderjs/holder.min.js
6
- ---
@@ -1,4 +0,0 @@
1
- ---
2
- t:title: resetApiKey
3
- layout: sumba.layout:/wide.html
4
- ---
@@ -1,57 +0,0 @@
1
- async function mergeSetting (req) {
2
- const { defaultsDeep, parseObject } = this.app.bajo
3
- const { trim, get, filter } = this.lib._
4
- const { recordFind, recordGet } = this.app.dobo
5
- const defSetting = {}
6
- const nsSetting = {}
7
- const query = {
8
- ns: { $in: this.app.bajo.pluginNames },
9
- siteId: req.site.id
10
- }
11
- const all = await recordFind('SumbaSiteSetting', { query, limit: -1 })
12
- for (const ns of this.app.bajo.pluginNames) {
13
- nsSetting[ns] = {}
14
- defSetting[ns] = get(this, `app.${ns}.config.siteSetting`, {})
15
- const items = filter(all, { ns })
16
- for (const item of items) {
17
- let value = trim([item.value] ?? '')
18
- if (['[', '{'].includes(value[0])) value = JSON.parse(value)
19
- else if (Number(value)) value = Number(value)
20
- else if (['true', 'false'].includes(value)) value = value === 'true'
21
- nsSetting[ns][item.key] = value
22
- }
23
- }
24
- req.site.setting = parseObject(defaultsDeep({}, nsSetting, defSetting))
25
- // additional fields
26
- const country = await recordGet('CdbCountry', req.site.country, { noHook: true })
27
- req.site.countryName = (country ?? {}).name ?? req.site.country
28
- }
29
-
30
- const omitted = ['status']
31
-
32
- async function checkSiteId (req, reply) {
33
- const { omit } = this.lib._
34
- const { recordFind } = this.app.dobo
35
-
36
- if (!this.config.multiSite) {
37
- const resp = await recordFind('SumbaSite', { query: { alias: 'default' } }, { noHook: true })
38
- req.site = omit(resp[0], omitted)
39
- await mergeSetting.call(this, req)
40
- return
41
- }
42
- const hostname = req.hostname.split(':')[0]
43
- const query = {
44
- $or: [
45
- { hostname },
46
- { alias: hostname }
47
- ]
48
- }
49
- const filter = { query, limit: 1 }
50
- const rows = await recordFind('SumbaSite', filter, { noHook: true })
51
- if (rows.length === 0) throw this.error('unknownSite')
52
- const row = omit(rows[0], omitted)
53
- if (row.status !== 'ACTIVE') throw this.error('siteInactiveInfo')
54
- await mergeSetting.call(this, req)
55
- }
56
-
57
- export default checkSiteId