@live-change/user-frontend 0.8.34 → 0.8.36

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.
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <div v-if="additionalScopes.length > 0" class="w-full flex flex-row justify-content-center">
3
+ <div class="surface-card border-round shadow-2 p-4 w-30rem">
4
+ <div class="text-900 font-medium mb-3 text-xl mb-4">Google API Access</div>
5
+ <div v-if="currentAccess.length > 0">
6
+ <p class="mt-0 p-0 line-height-3">
7
+ You are currently granting us access to the following Google API features:
8
+ </p>
9
+ <ul>
10
+ <li v-for="scope in currentAccess">
11
+ {{ scope.split('/').pop() }}
12
+ </li>
13
+ </ul>
14
+ </div>
15
+ <div>
16
+ <p>
17
+ To use this feature, you need to grant us access to the Google APIs listed below:
18
+ </p>
19
+ <ul>
20
+ <li v-for="scope in additionalScopes" class="font-semibold text-gray-700">
21
+ {{ scope.split('/').pop().toUpperCase() }} API
22
+ </li>
23
+ </ul>
24
+ <p>
25
+ Click the button below to go to the Google page where you can grant access.
26
+ </p>
27
+ </div>
28
+ <router-link
29
+ @click="handleClick"
30
+ :to="{ name: 'user:googleAuthScopes', params: {
31
+ action: 'addOfflineAccessToken',
32
+ accessType: 'offline',
33
+ scopes: allScopes
34
+ } }">
35
+ <Button icon="pi pi-key" label="Google Authentication" />
36
+ </router-link>
37
+ </div>
38
+ </div>
39
+ <slot v-else></slot>
40
+ </template>
41
+
42
+ <script setup>
43
+
44
+ import Button from 'primevue/button'
45
+
46
+ import { onMounted, ref } from 'vue'
47
+ const isMounted = ref(false)
48
+ onMounted(() => isMounted.value = true)
49
+
50
+ import { computed, toRefs } from 'vue'
51
+ import { usePath, live } from "@live-change/vue3-ssr"
52
+
53
+ import { useRoute } from "vue-router"
54
+ const route = useRoute()
55
+
56
+ const savedRoute = route.fullPath
57
+
58
+ const props = defineProps({
59
+ scopes: {
60
+ type: Array,
61
+ required: true
62
+ },
63
+ saveRoute:{
64
+ type: Boolean,
65
+ default: false
66
+ }
67
+ })
68
+ const { scopes, saveRoute } = toRefs(props)
69
+
70
+ const path = usePath()
71
+ const [ offlineAccess ] = await Promise.all([
72
+ live(path.googleAuthentication.myUserOfflineAccess({}))
73
+ ])
74
+
75
+ const currentAccess = computed(() => offlineAccess.value?.scopes ?? [])
76
+ const additionalScopes = computed(() => scopes.value.filter(
77
+ scope => !currentAccess.value.includes(scope)
78
+ ))
79
+
80
+ const allScopes = computed(() => [...currentAccess.value, ...additionalScopes.value])
81
+
82
+ function handleClick() {
83
+ if(saveRoute.value) {
84
+ localStorage.afterGoogleAccessGained = savedRoute
85
+ }
86
+ }
87
+
88
+ </script>
89
+
90
+ <style>
91
+
92
+ </style>
@@ -0,0 +1,71 @@
1
+ <template>
2
+ <div class="w-full lg:w-6 md:w-9" v-shared-element:form="{ duration: '300ms', includeChildren: true }">
3
+ <div class="surface-card border-round shadow-2 p-4">
4
+ <div class="text-900 font-medium mb-3 text-xl mb-4">Signed In</div>
5
+ <p class="mt-0 p-0 line-height-3">
6
+ Congratulations! You added offline access to your account. Now your account have access to:
7
+ <ul>
8
+ <li v-for="access in accessList">
9
+ {{ access }}
10
+ </li>
11
+ </ul>
12
+ <!-- <pre>{{ offlineAccess }}</pre>-->
13
+ </p>
14
+ <div v-if="afterGoogleAccessGained" class="flex flex-row align-items-center">
15
+ <router-link :to="afterGoogleAccessGained" class="no-underline">
16
+ <Button label="Next" v-ripple />
17
+ </router-link>
18
+ <p class="ml-4" v-if="isMounted && redirectTime">
19
+ Redirect in {{ pluralize('second', Math.ceil((redirectTime - currentTime) / 1000), true) }}...
20
+ </p>
21
+ </div>
22
+ <div v-else>
23
+ Return to <router-link to="/">index page</router-link>.
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <script setup>
30
+
31
+ import Button from 'primevue/button'
32
+
33
+ import { onMounted, ref } from 'vue'
34
+ const isMounted = ref(false)
35
+ onMounted(() => isMounted.value = true)
36
+
37
+ import { computed } from 'vue'
38
+ import { currentTime } from "@live-change/frontend-base"
39
+
40
+ import { useRouter } from 'vue-router'
41
+ const router = useRouter()
42
+
43
+ import { usePath, live } from "@live-change/vue3-ssr"
44
+
45
+ import pluralize from 'pluralize'
46
+
47
+ const afterGoogleAccessGained = computed( () => isMounted.value && localStorage.afterGoogleAccessGained )
48
+ let redirectTime
49
+ onMounted(() => {
50
+ redirectTime = new Date(Date.now() + 10 * 1000)
51
+ setTimeout(() => {
52
+ if (afterGoogleAccessGained.value) {
53
+ localStorage.removeItem('afterGoogleAccessGained')
54
+ router.push(afterGoogleAccessGained.value)
55
+ }
56
+ }, redirectTime - Date.now())
57
+ })
58
+
59
+ const path = usePath()
60
+ const [ offlineAccess ] = await Promise.all([
61
+ live(path.googleAuthentication.myUserOfflineAccess({}))
62
+ ])
63
+
64
+ const accessList = computed(() => offlineAccess.value.scopes.map(
65
+ scope => scope.split('/').pop()
66
+ ))
67
+ </script>
68
+
69
+ <style>
70
+
71
+ </style>
@@ -0,0 +1,15 @@
1
+ export function routes(config = {}) {
2
+ const { prefix = '/', route = (r) => r } = config
3
+
4
+ return [
5
+
6
+ route({ name: 'user:google-access-gained', path: prefix + 'google-offline-access-gained',
7
+ component: () => import("./GoogleAccessGained.vue"), meta: { signedIn: true } }),
8
+
9
+ route({ name: 'user:get-google-access', path: prefix + 'get-google-access/:scopes*',
10
+ component: () => import("./GoogleAccess.vue"), meta: { signedIn: true }, props: true }),
11
+
12
+ ]
13
+ }
14
+
15
+ export default routes
@@ -9,6 +9,7 @@ import signRoutes from "./sign/routes.js"
9
9
  import connectedRoutes from "./connected/routes.js"
10
10
  import identificationRoutes from "./identification/routes.js"
11
11
  import deleteRoutes from "./delete/routes.js"
12
+ import googleAccessRoutes from "./google-access/routes.js"
12
13
  import { passwordResetRoutes, passwordChangeRoutes } from "./password/routes.js"
13
14
  import { notificationsSettingsRoutes, notificationsRoutes } from "./notifications/routes.js"
14
15
  import localeSettingsRoutes from "./locale/routes.js"
@@ -23,6 +24,7 @@ export function userRoutes(config = {}) {
23
24
  ...signRoutes(config),
24
25
  ...passwordResetRoutes(config),
25
26
  ...notificationsRoutes(config),
27
+ ...googleAccessRoutes(config),
26
28
 
27
29
  route({
28
30
  path: prefix + 'settings', meta: { pageType: 'wide' },
@@ -87,7 +89,7 @@ export function createRouter(app, config) {
87
89
  history: import.meta.env.SSR ? createMemoryHistory() : createWebHistory(),
88
90
  routes: [
89
91
  { name: 'index', path: '/', component: () => import('./Index.vue') },
90
- ...userRoutes(config),
92
+ ...userRoutes({ ...config, prefix: '/user/' }),
91
93
  ...dbAdminRoutes({ prefix: '/_db', route: r => ({ ...r, meta: { ...r.meta, raw: true }}) })
92
94
  ]
93
95
  })
@@ -50,13 +50,13 @@
50
50
  type: String,
51
51
  default: 'offline', //'online'
52
52
  },
53
- scope: {
53
+ scopes: {
54
54
  type: Array,
55
55
  default: () => ['profile', 'email']
56
56
  }
57
57
  })
58
58
 
59
- const { action, accessType, scope } = toRefs(props)
59
+ const { action, accessType, scopes } = toRefs(props)
60
60
  const state = ref('waiting')
61
61
  const error = ref(null)
62
62
 
@@ -73,7 +73,7 @@
73
73
  }))
74
74
 
75
75
  googleAuthRedirect({
76
- scope: scope.value.join(' '),
76
+ scope: scopes.value.join(' '),
77
77
  redirectUri: document.location.protocol + '//' + document.location.host
78
78
  + router.resolve({ name: 'user:googleAuthReturn', params: { action: action.value } }).href,
79
79
  accessType: accessType.value
@@ -72,7 +72,7 @@
72
72
  )
73
73
  console.log("GAUTH RESULT", result)
74
74
  const { action: actionDone, user } = result
75
- while(api.client.value.user !== result.user) {
75
+ while(user && api.client.value.user !== user) {
76
76
  await new Promise(resolve => setTimeout(resolve, 100))
77
77
  }
78
78
  if(actionDone === 'signIn') {
@@ -81,6 +81,8 @@
81
81
  router.push({ name: 'user:signUpFinished' })
82
82
  } else if(actionDone === 'connectGoogle') {
83
83
  router.push({ name: 'user:connected' })
84
+ } else if(actionDone === 'addOfflineAccessToken') {
85
+ router.push({ name: 'user:google-access-gained' })
84
86
  } else {
85
87
  console.error("Unknown action", actionDone)
86
88
  }
package/index.js CHANGED
@@ -14,4 +14,7 @@ export { UserIcon }
14
14
  import Password from "./front/src/password/Password.vue"
15
15
  export { Password }
16
16
 
17
+ import GoogleAccess from './front/src/google-access/GoogleAccess.vue'
18
+ export { GoogleAccess }
19
+
17
20
  export * from "./front/src/router.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/user-frontend",
3
- "version": "0.8.34",
3
+ "version": "0.8.36",
4
4
  "scripts": {
5
5
  "memDev": "node --inspect --expose-gc server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
6
6
  "localDevInit": "rm tmp.db; node server/start.js localDev --enableSessions --initScript ./init.js",
@@ -22,29 +22,29 @@
22
22
  },
23
23
  "type": "module",
24
24
  "dependencies": {
25
- "@live-change/cli": "^0.8.34",
26
- "@live-change/dao": "^0.8.34",
27
- "@live-change/dao-vue3": "^0.8.34",
28
- "@live-change/dao-websocket": "^0.8.34",
29
- "@live-change/email-service": "^0.8.34",
30
- "@live-change/framework": "^0.8.34",
31
- "@live-change/identicon-service": "^0.8.34",
32
- "@live-change/image-frontend": "^0.8.34",
33
- "@live-change/message-authentication-service": "^0.8.34",
34
- "@live-change/notification-service": "^0.8.34",
35
- "@live-change/password-authentication-service": "^0.8.34",
36
- "@live-change/pattern": "^0.8.34",
37
- "@live-change/secret-code-service": "^0.8.34",
38
- "@live-change/secret-link-service": "^0.8.34",
39
- "@live-change/security-frontend": "^0.8.34",
40
- "@live-change/security-service": "^0.8.34",
41
- "@live-change/session-service": "^0.8.34",
42
- "@live-change/timer-service": "^0.8.34",
43
- "@live-change/upload-service": "^0.8.34",
44
- "@live-change/user-identification-service": "^0.8.34",
45
- "@live-change/user-service": "^0.8.34",
46
- "@live-change/vue3-components": "^0.8.34",
47
- "@live-change/vue3-ssr": "^0.8.34",
25
+ "@live-change/cli": "^0.8.36",
26
+ "@live-change/dao": "^0.8.36",
27
+ "@live-change/dao-vue3": "^0.8.36",
28
+ "@live-change/dao-websocket": "^0.8.36",
29
+ "@live-change/email-service": "^0.8.36",
30
+ "@live-change/framework": "^0.8.36",
31
+ "@live-change/identicon-service": "^0.8.36",
32
+ "@live-change/image-frontend": "^0.8.36",
33
+ "@live-change/message-authentication-service": "^0.8.36",
34
+ "@live-change/notification-service": "^0.8.36",
35
+ "@live-change/password-authentication-service": "^0.8.36",
36
+ "@live-change/pattern": "^0.8.36",
37
+ "@live-change/secret-code-service": "^0.8.36",
38
+ "@live-change/secret-link-service": "^0.8.36",
39
+ "@live-change/security-frontend": "^0.8.36",
40
+ "@live-change/security-service": "^0.8.36",
41
+ "@live-change/session-service": "^0.8.36",
42
+ "@live-change/timer-service": "^0.8.36",
43
+ "@live-change/upload-service": "^0.8.36",
44
+ "@live-change/user-identification-service": "^0.8.36",
45
+ "@live-change/user-service": "^0.8.36",
46
+ "@live-change/vue3-components": "^0.8.36",
47
+ "@live-change/vue3-ssr": "^0.8.36",
48
48
  "@vueuse/core": "^10.11.0",
49
49
  "codeceptjs-assert": "^0.0.5",
50
50
  "codeceptjs-video-helper": "0.1.3",
@@ -65,7 +65,7 @@
65
65
  "wtfnode": "^0.9.1"
66
66
  },
67
67
  "devDependencies": {
68
- "@live-change/codeceptjs-helper": "^0.8.34",
68
+ "@live-change/codeceptjs-helper": "^0.8.36",
69
69
  "codeceptjs": "^3.5.12",
70
70
  "generate-password": "1.7.1",
71
71
  "playwright": "^1.41.2",
@@ -76,5 +76,5 @@
76
76
  "author": "Michał Łaszczewski <michal@laszczewski.pl>",
77
77
  "license": "BSD-3-Clause",
78
78
  "description": "",
79
- "gitHead": "40e61928bf43b35352c76fc135f36a2d8bd76c4a"
79
+ "gitHead": "24694d1687f0ab2d6eb7edd95e5274428cfd44eb"
80
80
  }
@@ -1,6 +1,9 @@
1
1
  import App from "@live-change/framework"
2
2
  const app = App.app()
3
3
 
4
+ import dotenv from 'dotenv'
5
+ dotenv.config()
6
+
4
7
  const contactTypes = ['email', 'phone']
5
8
  const remoteAccountTypes = ['google']
6
9
 
@@ -86,11 +89,11 @@ app.config = {
86
89
  name: 'image',
87
90
  path: '@live-change/image-service'
88
91
  },
89
- {
92
+ /* {
90
93
  name: 'backup',
91
94
  path: '@live-change/backup-service',
92
95
  clearEvents: true
93
- }
96
+ }*/
94
97
 
95
98
  // { path: '@live-change/google-account-service' },
96
99
  ]
@@ -1,3 +1,4 @@
1
+ import timer from '@live-change/timer-service'
1
2
  import session from '@live-change/session-service'
2
3
  import user from '@live-change/user-service'
3
4
  import email from '@live-change/email-service'
@@ -15,10 +16,11 @@ import secretLink from '@live-change/secret-link-service'
15
16
  import messageAuthentication from '@live-change/message-authentication-service'
16
17
  import googleAuthentication from '@live-change/google-authentication-service'
17
18
 
18
- import backup from '@live-change/backup-service'
19
+ //import backup from '@live-change/backup-service'
19
20
  import init from './init.js'
20
21
 
21
22
  export {
23
+ timer,
22
24
  session,
23
25
  user,
24
26
  email,
@@ -35,6 +37,6 @@ export {
35
37
  messageAuthentication,
36
38
  googleAuthentication,
37
39
  localeSettings,
38
- backup,
40
+ // backup,
39
41
  init
40
42
  }