Adding sync user endpoint to server which can be used by the worker.

This commit is contained in:
Michael Drury 2021-11-03 23:15:38 +00:00
parent 311fe5f2eb
commit 3a5e004f36
5 changed files with 90 additions and 27 deletions

View File

@ -152,6 +152,17 @@ exports.getDeployedAppID = appId => {
return appId
}
/**
* Convert a deployed app ID to a development app ID.
*/
exports.getDevelopmentAppID = appId => {
if (!appId.startsWith(exports.APP_DEV_PREFIX)) {
const id = appId.split(exports.APP_PREFIX)[1]
return `${exports.APP_DEV_PREFIX}${id}`
}
return appId
}
exports.getCouchUrl = () => {
if (!env.COUCH_DB_URL) return

View File

@ -4,12 +4,14 @@ const {
getUserMetadataParams,
} = require("../../db/utils")
const { InternalTables } = require("../../db/utils")
const { getGlobalUsers } = require("../../utilities/global")
const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global")
const { getFullUser } = require("../../utilities/users")
const { isEqual } = require("lodash")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { getDevelopmentAppID } = require("@budibase/auth/db")
const { doesDatabaseExist } = require("../../utilities")
exports.rawMetadata = async db => {
async function rawMetadata(db) {
return (
await db.allDocs(
getUserMetadataParams(null, {
@ -19,45 +21,80 @@ exports.rawMetadata = async db => {
).rows.map(row => row.doc)
}
async function combineMetadataAndUser(user, metadata) {
// skip users with no access
if (user.roleId === BUILTIN_ROLE_IDS.PUBLIC) {
return null
}
delete user._rev
const metadataId = generateUserMetadataID(user._id)
const newDoc = {
...user,
_id: metadataId,
tableId: InternalTables.USER_METADATA,
}
const found = Array.isArray(metadata)
? metadata.find(doc => doc._id === metadataId)
: metadata
// copy rev over for the purposes of equality check
if (found) {
newDoc._rev = found._rev
}
if (found == null || !isEqual(newDoc, found)) {
return {
...found,
...newDoc,
}
}
return null
}
exports.syncGlobalUsers = async appId => {
// sync user metadata
const db = new CouchDB(appId)
const [users, metadata] = await Promise.all([
getGlobalUsers(appId),
exports.rawMetadata(db),
rawMetadata(db),
])
const toWrite = []
for (let user of users) {
// skip users with no access
if (user.roleId === BUILTIN_ROLE_IDS.PUBLIC) {
continue
}
delete user._rev
const metadataId = generateUserMetadataID(user._id)
const newDoc = {
...user,
_id: metadataId,
tableId: InternalTables.USER_METADATA,
}
const found = metadata.find(doc => doc._id === metadataId)
// copy rev over for the purposes of equality check
if (found) {
newDoc._rev = found._rev
}
if (found == null || !isEqual(newDoc, found)) {
toWrite.push({
...found,
...newDoc,
})
const combined = await combineMetadataAndUser(user, metadata)
if (combined) {
toWrite.push(combined)
}
}
await db.bulkDocs(toWrite)
}
exports.syncUser = async function (ctx) {
const user = await getRawGlobalUser(ctx.params.id)
const roles = user.roles
delete user.roles
for (let [prodAppId, roleId] of Object.entries(roles)) {
if (roleId === BUILTIN_ROLE_IDS.PUBLIC) {
continue
}
const devAppId = getDevelopmentAppID(prodAppId)
for (let appId of [prodAppId, devAppId]) {
if (!(await doesDatabaseExist(appId))) {
continue
}
const db = new CouchDB(appId)
const userId = generateUserMetadataID(user._id)
const metadata = await db.get(userId)
const combined = combineMetadataAndUser(user, metadata)
await db.put(combined)
}
}
ctx.body = {
message: "User synced.",
}
}
exports.fetchMetadata = async function (ctx) {
const database = new CouchDB(ctx.appId)
const global = await getGlobalUsers(ctx.appId)
const metadata = await exports.rawMetadata(database)
const metadata = await rawMetadata(database)
const users = []
for (let user of global) {
// find the metadata that matches up to the global ID

View File

@ -34,5 +34,10 @@ router
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
controller.destroyMetadata
)
.post(
"/api/users/sync/:id",
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
controller.syncUser
)
module.exports = router

View File

@ -46,9 +46,13 @@ exports.getCachedSelf = async (ctx, appId) => {
return processUser(appId, user)
}
exports.getGlobalUser = async (appId, userId) => {
exports.getRawGlobalUser = async userId => {
const db = getGlobalDB()
let user = await db.get(getGlobalIDFromUserMetadataID(userId))
return db.get(getGlobalIDFromUserMetadataID(userId))
}
exports.getGlobalUser = async (appId, userId) => {
let user = await exports.getRawGlobalUser(userId)
return processUser(appId, user)
}

View File

@ -134,3 +134,9 @@ exports.stringToReadStream = string => {
},
})
}
exports.doesDatabaseExist = async dbName => {
const db = new CouchDB(dbName, { skip_setup: true })
const info = await db.info()
return info && !info.error
}