7a137 google auth (#520)
* google oauth * fix lint * cleanup debug * Oauth changes, alert message, email validation * fix exception and inline return condition * fix google oauth * UI fixes * fix provider user --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
/>
|
||||
|
||||
<!-- Remember Me -->
|
||||
<div class="relative flex items-center my-5">
|
||||
<div class="relative flex items-start mt-5">
|
||||
<CheckboxInput
|
||||
v-model="remember"
|
||||
class="w-full md:w-1/2"
|
||||
@@ -52,15 +52,28 @@
|
||||
|
||||
<!-- Submit Button -->
|
||||
<v-button
|
||||
dusk="btn_login"
|
||||
class="w-full flex"
|
||||
:loading="form.busy || loading"
|
||||
>
|
||||
Log in to continue
|
||||
</v-button>
|
||||
|
||||
<v-button
|
||||
native-type="button"
|
||||
color="white"
|
||||
class="space-x-4 mt-4 flex items-center w-full"
|
||||
:loading="false"
|
||||
@click.prevent="signInwithGoogle"
|
||||
>
|
||||
<Icon
|
||||
name="devicon:google"
|
||||
class="w-4 h-4 -mt-1"
|
||||
/>
|
||||
<span class="mx-2">Sign in with Google</span>
|
||||
</v-button>
|
||||
<p
|
||||
v-if="!appStore.selfHosted"
|
||||
class="text-gray-500 mt-4"
|
||||
class="text-gray-500 text-sm text-center mt-4"
|
||||
>
|
||||
Don't have an account?
|
||||
<a
|
||||
@@ -106,6 +119,7 @@ export default {
|
||||
authStore: useAuthStore(),
|
||||
formsStore: useFormsStore(),
|
||||
workspaceStore: useWorkspacesStore(),
|
||||
providersStore: useOAuthProvidersStore()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -119,6 +133,8 @@ export default {
|
||||
showForgotModal: false,
|
||||
}),
|
||||
|
||||
computed: {},
|
||||
|
||||
methods: {
|
||||
login() {
|
||||
// Submit the form.
|
||||
@@ -170,6 +186,9 @@ export default {
|
||||
router.push({ name: "home" })
|
||||
}
|
||||
},
|
||||
signInwithGoogle() {
|
||||
this.providersStore.guestConnect('google', true)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<form
|
||||
class="mt-4"
|
||||
@submit.prevent="register"
|
||||
@keydown="form.onKeydown($event)"
|
||||
>
|
||||
@@ -56,6 +55,7 @@
|
||||
<checkbox-input
|
||||
:form="form"
|
||||
name="agree_terms"
|
||||
class="mb-3"
|
||||
:required="true"
|
||||
>
|
||||
<template #label>
|
||||
@@ -63,6 +63,7 @@
|
||||
<NuxtLink
|
||||
:to="{ name: 'terms-conditions' }"
|
||||
target="_blank"
|
||||
class="underline"
|
||||
>
|
||||
Terms and conditions
|
||||
</NuxtLink>
|
||||
@@ -70,6 +71,7 @@
|
||||
<NuxtLink
|
||||
:to="{ name: 'privacy-policy' }"
|
||||
target="_blank"
|
||||
class="underline"
|
||||
>
|
||||
Privacy policy
|
||||
</NuxtLink>
|
||||
@@ -78,16 +80,33 @@
|
||||
</checkbox-input>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<v-button :loading="form.busy">
|
||||
Create an account
|
||||
<v-button
|
||||
class="w-full mt-4"
|
||||
:loading="form.busy"
|
||||
>
|
||||
Create account
|
||||
</v-button>
|
||||
|
||||
<p class="text-gray-500 mt-4">
|
||||
<p class="text-gray-600/50 text-sm text-center my-4">
|
||||
Or
|
||||
</p>
|
||||
<v-button
|
||||
native-type="buttom"
|
||||
color="white"
|
||||
class="space-x-4 flex items-center w-full"
|
||||
:loading="false"
|
||||
@click.prevent="signInwithGoogle"
|
||||
>
|
||||
<Icon name="devicon:google" />
|
||||
<span class="mx-2">Sign in with Google</span>
|
||||
</v-button>
|
||||
|
||||
<p class="text-gray-500 mt-4 text-sm text-center">
|
||||
Already have an account?
|
||||
<a
|
||||
v-if="isQuick"
|
||||
href="#"
|
||||
class="font-semibold ml-1"
|
||||
class="font-medium ml-1"
|
||||
@click.prevent="$emit('openLogin')"
|
||||
>Log In</a>
|
||||
<NuxtLink
|
||||
@@ -123,6 +142,7 @@ export default {
|
||||
authStore: useAuthStore(),
|
||||
formsStore: useFormsStore(),
|
||||
workspaceStore: useWorkspacesStore(),
|
||||
providersStore: useOAuthProvidersStore(),
|
||||
logEvent: useAmplitude().logEvent,
|
||||
}
|
||||
},
|
||||
@@ -241,6 +261,9 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
signInwithGoogle() {
|
||||
this.providersStore.guestConnect('google', true)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
1
client/middleware/self-hosted.js
vendored
1
client/middleware/self-hosted.js
vendored
@@ -2,7 +2,6 @@ export default defineNuxtRouteMiddleware((from, to, next) => {
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const route = useRoute()
|
||||
if (runtimeConfig.public?.selfHosted) {
|
||||
console.log('in')
|
||||
if (from.name === 'register' && route.query?.email && route.query?.invite_token) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
<h2 class="font-semibold text-2xl">
|
||||
Login to OpnForm
|
||||
</h2>
|
||||
<small>Welcome back! Please enter your details.</small>
|
||||
<p class="text-sm text-gray-500">
|
||||
Welcome back! Please enter your details.
|
||||
</p>
|
||||
|
||||
<login-form />
|
||||
</div>
|
||||
|
||||
92
client/pages/oauth/callback.vue
Normal file
92
client/pages/oauth/callback.vue
Normal file
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="flex flex-grow mt-6 mb-10">
|
||||
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md px-4">
|
||||
<div class="m-10" v-if="loading">
|
||||
<h3 class="my-6 text-center">
|
||||
Please wait...
|
||||
</h3>
|
||||
<Loader class="h-6 w-6 mx-auto m-10" />
|
||||
</div>
|
||||
<div class="m-6 flex flex-col items-center space-y-4" v-else>
|
||||
<p class="text-center"> Unable to sign it at the moment. </p>
|
||||
<v-button
|
||||
:to="{ name: 'login' }"
|
||||
>Back to login</v-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const authStore = useAuthStore()
|
||||
const workspacesStore = useWorkspacesStore()
|
||||
const formsStore = useFormsStore()
|
||||
const logEvent = useAmplitude().logEvent
|
||||
const loading = ref(true);
|
||||
|
||||
definePageMeta({
|
||||
alias: [
|
||||
'/oauth/:provider/callback'
|
||||
]
|
||||
})
|
||||
|
||||
function handleCallback() {
|
||||
|
||||
const code = route.query.code
|
||||
const provider = route.params.provider
|
||||
opnFetch(`/oauth/${provider}/callback`, {
|
||||
method: 'POST',
|
||||
params: {
|
||||
code
|
||||
}
|
||||
}).then(async (data) => {
|
||||
authStore.setToken(data.token)
|
||||
const [userDataResponse, workspacesResponse] = await Promise.all([
|
||||
opnFetch("user"),
|
||||
fetchAllWorkspaces(),
|
||||
])
|
||||
authStore.setUser(userDataResponse)
|
||||
workspacesStore.set(workspacesResponse.data.value)
|
||||
|
||||
// Load forms
|
||||
formsStore.loadAll(workspacesStore.currentId)
|
||||
if (!data.new_user) {
|
||||
logEvent("login", { source: provider })
|
||||
try {
|
||||
useGtm().trackEvent({
|
||||
event: 'login',
|
||||
source: provider
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
router.push({ name: "home" })
|
||||
return
|
||||
} else {
|
||||
logEvent("register", { source: provider })
|
||||
router.push({ name: "forms-create" })
|
||||
useAlert().success("Success! You're now registered with your Google account! Welcome to OpnForm.")
|
||||
try {
|
||||
useGtm().trackEvent({
|
||||
event: 'register',
|
||||
source: provider
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
useAlert().error(error)
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
useAlert().error(error.response._data.message)
|
||||
loading.value = false;
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
handleCallback()
|
||||
})
|
||||
|
||||
</script>
|
||||
@@ -10,7 +10,9 @@
|
||||
<h2 class="font-semibold text-2xl">
|
||||
Create an account
|
||||
</h2>
|
||||
<small>Sign up in less than 2 minutes.</small>
|
||||
<p class="text-gray-500 text-sm">
|
||||
Sign up in less than 2 minutes.
|
||||
</p>
|
||||
<template v-if="!appStore.selfHosted || isInvited">
|
||||
<register-form />
|
||||
</template>
|
||||
|
||||
30
client/stores/oauth_providers.js
vendored
30
client/stores/oauth_providers.js
vendored
@@ -61,6 +61,33 @@ export const useOAuthProvidersStore = defineStore("oauth_providers", () => {
|
||||
})
|
||||
}
|
||||
|
||||
const guestConnect = (service, redirect = false) => {
|
||||
contentStore.resetState()
|
||||
contentStore.startLoading()
|
||||
|
||||
const intention = new URL(window.location.href).pathname
|
||||
|
||||
opnFetch(`/oauth/connect/${service}`, {
|
||||
method: 'POST',
|
||||
body: {
|
||||
...redirect ? { intention } : {},
|
||||
}
|
||||
})
|
||||
.then((data) => {
|
||||
window.location.href = data.url
|
||||
})
|
||||
.catch((error) => {
|
||||
try {
|
||||
alert.error(error.data.message)
|
||||
} catch (e) {
|
||||
alert.error("An error occurred while connecting an account")
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
contentStore.stopLoading()
|
||||
})
|
||||
}
|
||||
|
||||
const providers = computed(() => contentStore.getAll.value)
|
||||
|
||||
return {
|
||||
@@ -69,6 +96,7 @@ export const useOAuthProvidersStore = defineStore("oauth_providers", () => {
|
||||
getService,
|
||||
fetchOAuthProviders,
|
||||
providers,
|
||||
connect
|
||||
connect,
|
||||
guestConnect
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user