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:
Favour Olayinka
2024-08-19 14:22:57 +01:00
committed by GitHub
parent 5049ba7fb1
commit 7ac8503201
14 changed files with 273 additions and 52 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
}

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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
}
})