sync third party profile on every login

This commit is contained in:
Rory Powell 2021-07-08 16:11:48 +01:00
parent 7db8658518
commit 8bea18e696
1 changed files with 48 additions and 26 deletions

View File

@ -30,6 +30,7 @@ exports.authenticateThirdParty = async function (
// use the third party id // use the third party id
const userId = generateGlobalUserID(thirdPartyUser.userId) const userId = generateGlobalUserID(thirdPartyUser.userId)
// try to load by id
try { try {
dbUser = await db.get(userId) dbUser = await db.get(userId)
} catch (err) { } catch (err) {
@ -41,39 +42,45 @@ exports.authenticateThirdParty = async function (
err err
) )
} }
}
// check user already exists by email // fallback to loading by email
if (!dbUser) {
const users = await db.query(`database/${ViewNames.USER_BY_EMAIL}`, { const users = await db.query(`database/${ViewNames.USER_BY_EMAIL}`, {
key: thirdPartyUser.email, key: thirdPartyUser.email,
include_docs: true, include_docs: true,
}) })
const userExists = users.rows.length > 0
if (requireLocalAccount && !userExists) { if (users.rows.length > 0) {
dbUser = users.rows[0].doc
}
}
// exit early if there is still no user and auto creation is disabled
if (!dbUser && requireLocalAccount ) {
if (requireLocalAccount) {
return authError( return authError(
done, done,
"Email does not yet exist. You must set up your local budibase account first." "Email does not yet exist. You must set up your local budibase account first."
) )
} }
// create the user to save
let user
if (userExists) {
const existing = users.rows[0].doc
user = constructMergedUser(userId, existing, thirdPartyUser)
// remove the local account to avoid conflicts
await db.remove(existing._id, existing._rev)
} else {
user = constructNewUser(userId, thirdPartyUser)
}
// save the user
const response = await db.post(user)
dbUser = user
dbUser._rev = response.rev
} }
let user
// first time creation
if (!dbUser) {
user = constructNewUser(userId, thirdPartyUser)
} else {
// existing user
user = constructMergedUser(userId, dbUser, thirdPartyUser)
await db.remove(dbUser._id, dbUser._rev)
}
// create or sync the user
const response = await db.post(user)
dbUser = user
dbUser._rev = response.rev
// authenticate // authenticate
const payload = { const payload = {
userId: dbUser._id, userId: dbUser._id,
@ -92,9 +99,10 @@ exports.authenticateThirdParty = async function (
* @returns a user object constructed from existing and third party information * @returns a user object constructed from existing and third party information
*/ */
function constructMergedUser(userId, existing, thirdPartyUser) { function constructMergedUser(userId, existing, thirdPartyUser) {
// sync third party fields
const user = constructNewUser(userId, thirdPartyUser) const user = constructNewUser(userId, thirdPartyUser)
// merge with existing account // merge existing fields
user.roles = existing.roles user.roles = existing.roles
user.builder = existing.builder user.builder = existing.builder
user.admin = existing.admin user.admin = existing.admin
@ -114,13 +122,27 @@ function constructNewUser(userId, thirdPartyUser) {
roles: {}, roles: {},
} }
// persist profile information
// @reviewers: Historically stored at the root level of the user
// Nest to prevent conflicts with future fields
// Is this okay to change?
if (thirdPartyUser.profile) { if (thirdPartyUser.profile) {
const profile = thirdPartyUser.profile
if (profile.name) {
const name = profile.name
// first name
if (name.givenName) {
user.firstName = name.givenName
}
// last name
if (name.familyName) {
user.lastName = name.familyName
}
}
// profile
// @reviewers: Historically stored at the root level of the user
// Nest to prevent conflicts with future fields
// Is this okay to change?
user.thirdPartyProfile = { user.thirdPartyProfile = {
...thirdPartyUser.profile._json, ...profile._json,
} }
} }