lint
This commit is contained in:
parent
25a395972c
commit
dfdee4d271
|
@ -0,0 +1,64 @@
|
||||||
|
import { publishEvent } from "../events"
|
||||||
|
import {
|
||||||
|
Event,
|
||||||
|
UserGroup,
|
||||||
|
GroupCreatedEvent,
|
||||||
|
GroupDeletedEvent,
|
||||||
|
GroupUpdatedEvent,
|
||||||
|
GroupUsersAddedEvent,
|
||||||
|
GroupUsersDeletedEvent,
|
||||||
|
GroupsAddedOnboarding,
|
||||||
|
UserGroupRoles,
|
||||||
|
} from "@budibase/types"
|
||||||
|
|
||||||
|
export async function created(group: UserGroup, timestamp?: number) {
|
||||||
|
const properties: GroupCreatedEvent = {
|
||||||
|
groupId: group._id as string,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.USER_GROUP_CREATED, properties, timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updated(group: UserGroup) {
|
||||||
|
const properties: GroupUpdatedEvent = {
|
||||||
|
groupId: group._id as string,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.USER_GROUP_UPDATED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleted(group: UserGroup) {
|
||||||
|
const properties: GroupDeletedEvent = {
|
||||||
|
groupId: group._id as string,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.USER_GROUP_DELETED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function usersAdded(emails: string[], group: UserGroup) {
|
||||||
|
const properties: GroupUsersAddedEvent = {
|
||||||
|
emails,
|
||||||
|
count: emails.length,
|
||||||
|
groupId: group._id as string,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.USER_GROUP_USER_ADDED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function usersDeleted(emails: string[], group: UserGroup) {
|
||||||
|
const properties: GroupUsersDeletedEvent = {
|
||||||
|
emails,
|
||||||
|
count: emails.length,
|
||||||
|
groupId: group._id as string,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.USER_GROUP_USER_REMOVED, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createdOnboarding(groupId: string) {
|
||||||
|
const properties: GroupsAddedOnboarding = {
|
||||||
|
groupId: groupId,
|
||||||
|
onboarding: true,
|
||||||
|
}
|
||||||
|
await publishEvent(Event.USER_GROUP_ONBOARDING, properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function permissionsEdited(roles: UserGroupRoles) {
|
||||||
|
const properties: UserGroupRoles = roles
|
||||||
|
await publishEvent(Event.USER_GROUP_PERMISSIONS_EDITED, properties)
|
||||||
|
}
|
|
@ -17,3 +17,4 @@ export * as user from "./user"
|
||||||
export * as view from "./view"
|
export * as view from "./view"
|
||||||
export * as installation from "./installation"
|
export * as installation from "./installation"
|
||||||
export * as backfill from "./backfill"
|
export * as backfill from "./backfill"
|
||||||
|
export * as group from "./group"
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
let user = await users.get(id)
|
let user = await users.get(id)
|
||||||
|
|
||||||
let userGroups = user.groups || []
|
let userGroups = user.userGroups || []
|
||||||
userGroups.push(groupId)
|
userGroups.push(groupId)
|
||||||
await users.save({
|
await users.save({
|
||||||
...user,
|
...user,
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export * from "./config"
|
export * from "./config"
|
||||||
export * from "./user"
|
export * from "./user"
|
||||||
|
export * from "./userGroup"
|
||||||
|
|
|
@ -13,6 +13,7 @@ export interface User extends Document {
|
||||||
providerType?: string
|
providerType?: string
|
||||||
password?: string
|
password?: string
|
||||||
status?: string
|
status?: string
|
||||||
|
|
||||||
createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now()
|
createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Document } from "../document"
|
||||||
|
import { User } from "./user"
|
||||||
|
export interface UserGroup extends Document {
|
||||||
|
name: string
|
||||||
|
icon: string
|
||||||
|
color: string
|
||||||
|
users: User[]
|
||||||
|
apps: any
|
||||||
|
roles: UserGroupRoles
|
||||||
|
createdAt?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserGroupRoles {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
|
@ -150,6 +150,15 @@ export enum Event {
|
||||||
TENANT_BACKFILL_FAILED = "tenant:backfill:failed",
|
TENANT_BACKFILL_FAILED = "tenant:backfill:failed",
|
||||||
INSTALLATION_BACKFILL_SUCCEEDED = "installation:backfill:succeeded",
|
INSTALLATION_BACKFILL_SUCCEEDED = "installation:backfill:succeeded",
|
||||||
INSTALLATION_BACKFILL_FAILED = "installation:backfill:failed",
|
INSTALLATION_BACKFILL_FAILED = "installation:backfill:failed",
|
||||||
|
|
||||||
|
// USER
|
||||||
|
USER_GROUP_CREATED = "user_group:created",
|
||||||
|
USER_GROUP_UPDATED = "user_group:updated",
|
||||||
|
USER_GROUP_DELETED = "user_group:deleted",
|
||||||
|
USER_GROUP_USER_ADDED = "user_group_user:added",
|
||||||
|
USER_GROUP_USER_REMOVED = "user_group_user:deleted",
|
||||||
|
USER_GROUP_PERMISSIONS_EDITED = "user_group_permissions:edited",
|
||||||
|
USER_GROUP_ONBOARDING = "user_group_onboarding:added",
|
||||||
}
|
}
|
||||||
|
|
||||||
// properties added at the final stage of the event pipeline
|
// properties added at the final stage of the event pipeline
|
||||||
|
|
|
@ -18,3 +18,4 @@ export * from "./view"
|
||||||
export * from "./account"
|
export * from "./account"
|
||||||
export * from "./backfill"
|
export * from "./backfill"
|
||||||
export * from "./identification"
|
export * from "./identification"
|
||||||
|
export * from "./userGroup"
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { BaseEvent } from "./event"
|
||||||
|
|
||||||
|
export interface GroupCreatedEvent extends BaseEvent {
|
||||||
|
groupId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupUpdatedEvent extends BaseEvent {
|
||||||
|
groupId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupDeletedEvent extends BaseEvent {
|
||||||
|
groupId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupUsersAddedEvent extends BaseEvent {
|
||||||
|
emails: string[]
|
||||||
|
count: number
|
||||||
|
groupId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GroupsAddedOnboarding extends BaseEvent {
|
||||||
|
groupId: string
|
||||||
|
onboarding: boolean
|
||||||
|
}
|
|
@ -1,24 +1,64 @@
|
||||||
const { Configs } = require("../../../constants")
|
import { UserGroup } from "@budibase/types"
|
||||||
const email = require("../../../utilities/email")
|
const { difference } = require("lodash/fp")
|
||||||
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
|
|
||||||
const env = require("../../../environment")
|
const { events } = require("@budibase/backend-core")
|
||||||
const {
|
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
||||||
withCache,
|
|
||||||
CacheKeys,
|
|
||||||
bustCache,
|
|
||||||
} = require("@budibase/backend-core/cache")
|
|
||||||
const { groups } = require("@budibase/pro")
|
const { groups } = require("@budibase/pro")
|
||||||
|
|
||||||
exports.save = async function (ctx: any) {
|
exports.save = async function (ctx: any) {
|
||||||
const db = getGlobalDB()
|
const db = getGlobalDB()
|
||||||
|
let group: UserGroup = ctx.request.body
|
||||||
|
const oldGroup: UserGroup = await db.get(group._id)
|
||||||
|
|
||||||
|
let eventFns = []
|
||||||
// Config does not exist yet
|
// Config does not exist yet
|
||||||
if (!ctx.request.body._id) {
|
if (!group._id) {
|
||||||
ctx.request.body._id = groups.generateUserGroupID(ctx.request.body.name)
|
group._id = groups.generateUserGroupID(ctx.request.body.name)
|
||||||
|
eventFns.push(() => events.group.created(group))
|
||||||
|
} else {
|
||||||
|
// Get the diff between the old users and new users for
|
||||||
|
// event processing purposes
|
||||||
|
let uniqueOld = group.users.filter(g => {
|
||||||
|
return !oldGroup.users.some(og => {
|
||||||
|
return g._id == og._id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
let uniqueNew = oldGroup.users.filter(g => {
|
||||||
|
return !group.users.some(og => {
|
||||||
|
return g._id == og._id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let newUsers = uniqueOld.concat(uniqueNew)
|
||||||
|
|
||||||
|
eventFns.push(() => events.group.updated(group))
|
||||||
|
|
||||||
|
if (group.users.length < oldGroup.users.length) {
|
||||||
|
eventFns.push(() =>
|
||||||
|
events.group.usersDeleted(
|
||||||
|
newUsers.map(u => u.email),
|
||||||
|
group
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else if (group.users.length > oldGroup.users.length) {
|
||||||
|
eventFns.push(() =>
|
||||||
|
events.group.usersAdded(
|
||||||
|
newUsers.map(u => u.email),
|
||||||
|
group
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON.stringify(oldGroup.roles) !== JSON.stringify(group.roles)) {
|
||||||
|
eventFns.push(() => events.group.permissionsEdited(group.roles))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await db.put(ctx.request.body)
|
for (const fn of eventFns) {
|
||||||
|
await fn()
|
||||||
|
}
|
||||||
|
const response = await db.put(group)
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
_id: response.id,
|
_id: response.id,
|
||||||
_rev: response.rev,
|
_rev: response.rev,
|
||||||
|
@ -41,9 +81,10 @@ exports.fetch = async function (ctx: any) {
|
||||||
exports.destroy = async function (ctx: any) {
|
exports.destroy = async function (ctx: any) {
|
||||||
const db = getGlobalDB()
|
const db = getGlobalDB()
|
||||||
const { id, rev } = ctx.params
|
const { id, rev } = ctx.params
|
||||||
|
const group = await db.get(id)
|
||||||
try {
|
try {
|
||||||
await db.remove(id, rev)
|
await db.remove(id, rev)
|
||||||
|
await events.group.deleted(group)
|
||||||
ctx.body = { message: "Group deleted successfully" }
|
ctx.body = { message: "Group deleted successfully" }
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
ctx.throw(err.status, err)
|
ctx.throw(err.status, err)
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { checkInviteCode } from "../../../utilities/redis"
|
||||||
import { sendEmail } from "../../../utilities/email"
|
import { sendEmail } from "../../../utilities/email"
|
||||||
import { users } from "../../../sdk"
|
import { users } from "../../../sdk"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { User, CloudAccount } from "@budibase/types"
|
import { User, CloudAccount, UserGroup } from "@budibase/types"
|
||||||
import {
|
import {
|
||||||
events,
|
events,
|
||||||
errors,
|
errors,
|
||||||
|
@ -24,53 +24,54 @@ export const save = async (ctx: any) => {
|
||||||
|
|
||||||
export const bulkSave = async (ctx: any) => {
|
export const bulkSave = async (ctx: any) => {
|
||||||
let { users: newUsersRequested, groups } = ctx.request.body
|
let { users: newUsersRequested, groups } = ctx.request.body
|
||||||
let usersToSave: any[] = []
|
|
||||||
let groupsToSave: any[] = []
|
let groupsToSave: any[] = []
|
||||||
const newUsers: any[] = []
|
const newUsers: any[] = []
|
||||||
const db = tenancy.getGlobalDB()
|
const db = tenancy.getGlobalDB()
|
||||||
const currentUserEmails =
|
const currentUserEmails =
|
||||||
(await users.allUsers())?.map((x: any) => x.email) || []
|
(await users.allUsers())?.map((x: any) => x.email) || []
|
||||||
|
|
||||||
for (const newUser of newUsersRequested) {
|
for (const newUser of newUsersRequested) {
|
||||||
if (
|
if (
|
||||||
newUsers.find((x: any) => x.email === newUser.email) ||
|
newUsers.find((x: any) => x.email === newUser.email) ||
|
||||||
currentUserEmails.includes(newUser.email)
|
currentUserEmails.includes(newUser.email)
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
newUser.userGroups = groups
|
||||||
newUsers.push(newUser)
|
newUsers.push(newUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
newUsers.forEach((user: any) => {
|
if (groups.length) {
|
||||||
usersToSave.push(
|
groups.forEach(async (groupId: string) => {
|
||||||
users.save(user, {
|
let oldGroup = await db.get(groupId)
|
||||||
|
groupsToSave.push(oldGroup)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let response = []
|
||||||
|
for (const user of newUsers) {
|
||||||
|
response = await users.save(user, {
|
||||||
hashPassword: true,
|
hashPassword: true,
|
||||||
requirePassword: user.requirePassword,
|
requirePassword: user.requirePassword,
|
||||||
bulkCreate: true,
|
bulkCreate: false,
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
if (groups.length) {
|
|
||||||
groups.forEach(async (groupId: string) => {
|
|
||||||
let oldGroup = await db.get(groupId)
|
|
||||||
groupsToSave.push(oldGroup)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
try {
|
|
||||||
const allUsers = await Promise.all(usersToSave)
|
|
||||||
let response = await db.bulkDocs(allUsers)
|
|
||||||
|
|
||||||
// delete passwords and add to group
|
// delete passwords and add to group
|
||||||
allUsers.forEach(user => {
|
newUsers.forEach(user => {
|
||||||
delete user.password
|
delete user.password
|
||||||
})
|
})
|
||||||
|
|
||||||
if (groupsToSave.length)
|
if (groupsToSave.length) {
|
||||||
groupsToSave.forEach(async group => {
|
groupsToSave.forEach(async (userGroup: UserGroup) => {
|
||||||
group.users = [...group.users, ...allUsers]
|
userGroup.users = [...userGroup.users, ...newUsers]
|
||||||
await db.put(group)
|
await db.put(userGroup)
|
||||||
|
events.group.usersAdded(
|
||||||
|
newUsers.map(u => u.email),
|
||||||
|
userGroup
|
||||||
|
)
|
||||||
|
events.group.createdOnboarding(userGroup._id as string)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
ctx.body = response
|
ctx.body = response
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|
|
@ -31,9 +31,8 @@ export const allUsers = async () => {
|
||||||
|
|
||||||
export const paginatedUsers = async ({
|
export const paginatedUsers = async ({
|
||||||
page,
|
page,
|
||||||
email,
|
search,
|
||||||
appId,
|
}: { page?: string; search?: string } = {}) => {
|
||||||
}: { page?: string; email?: string; appId?: string } = {}) => {
|
|
||||||
const db = tenancy.getGlobalDB()
|
const db = tenancy.getGlobalDB()
|
||||||
// get one extra document, to have the next page
|
// get one extra document, to have the next page
|
||||||
const opts: any = {
|
const opts: any = {
|
||||||
|
@ -45,24 +44,19 @@ export const paginatedUsers = async ({
|
||||||
opts.startkey = page
|
opts.startkey = page
|
||||||
}
|
}
|
||||||
// property specifies what to use for the page/anchor
|
// property specifies what to use for the page/anchor
|
||||||
let userList,
|
let userList, property
|
||||||
property = "_id",
|
// no search, query allDocs
|
||||||
getKey
|
if (!search) {
|
||||||
if (appId) {
|
|
||||||
userList = await usersCore.searchGlobalUsersByApp(appId, opts)
|
|
||||||
getKey = (doc: any) => usersCore.getGlobalUserByAppPage(appId, doc)
|
|
||||||
} else if (email) {
|
|
||||||
userList = await usersCore.searchGlobalUsersByEmail(email, opts)
|
|
||||||
property = "email"
|
|
||||||
} else {
|
|
||||||
// no search, query allDocs
|
|
||||||
const response = await db.allDocs(dbUtils.getGlobalUserParams(null, opts))
|
const response = await db.allDocs(dbUtils.getGlobalUserParams(null, opts))
|
||||||
userList = response.rows.map((row: any) => row.doc)
|
userList = response.rows.map((row: any) => row.doc)
|
||||||
|
property = "_id"
|
||||||
|
} else {
|
||||||
|
userList = await usersCore.searchGlobalUsersByEmail(search, opts)
|
||||||
|
property = "email"
|
||||||
}
|
}
|
||||||
return dbUtils.pagination(userList, PAGE_LIMIT, {
|
return dbUtils.pagination(userList, PAGE_LIMIT, {
|
||||||
paginate: true,
|
paginate: true,
|
||||||
property,
|
property,
|
||||||
getKey,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue