Merge pull request #15327 from Budibase/type-portal-user-store-2
Convert portal user store to TS
This commit is contained in:
commit
0468dac7f9
|
@ -442,13 +442,11 @@
|
||||||
|
|
||||||
const onUpdateUserInvite = async (invite, role) => {
|
const onUpdateUserInvite = async (invite, role) => {
|
||||||
let updateBody = {
|
let updateBody = {
|
||||||
code: invite.code,
|
|
||||||
apps: {
|
apps: {
|
||||||
...invite.apps,
|
...invite.apps,
|
||||||
[prodAppId]: role,
|
[prodAppId]: role,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role === Constants.Roles.CREATOR) {
|
if (role === Constants.Roles.CREATOR) {
|
||||||
updateBody.builder = updateBody.builder || {}
|
updateBody.builder = updateBody.builder || {}
|
||||||
updateBody.builder.apps = [...(updateBody.builder.apps ?? []), prodAppId]
|
updateBody.builder.apps = [...(updateBody.builder.apps ?? []), prodAppId]
|
||||||
|
@ -456,7 +454,7 @@
|
||||||
} else if (role !== Constants.Roles.CREATOR && invite?.builder?.apps) {
|
} else if (role !== Constants.Roles.CREATOR && invite?.builder?.apps) {
|
||||||
invite.builder.apps = []
|
invite.builder.apps = []
|
||||||
}
|
}
|
||||||
await users.updateInvite(updateBody)
|
await users.updateInvite(invite.code, updateBody)
|
||||||
await filterInvites(query)
|
await filterInvites(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,8 +468,7 @@
|
||||||
let updated = { ...invite }
|
let updated = { ...invite }
|
||||||
delete updated.info.apps[prodAppId]
|
delete updated.info.apps[prodAppId]
|
||||||
|
|
||||||
return await users.updateInvite({
|
return await users.updateInvite(updated.code, {
|
||||||
code: updated.code,
|
|
||||||
apps: updated.apps,
|
apps: updated.apps,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,8 +191,14 @@
|
||||||
? "View errors"
|
? "View errors"
|
||||||
: "View error"}
|
: "View error"}
|
||||||
on:dismiss={async () => {
|
on:dismiss={async () => {
|
||||||
await automationStore.actions.clearLogErrors({ appId })
|
const automationId = Object.keys(automationErrors[appId] || {})[0]
|
||||||
await appsStore.load()
|
if (automationId) {
|
||||||
|
await automationStore.actions.clearLogErrors({
|
||||||
|
appId,
|
||||||
|
automationId,
|
||||||
|
})
|
||||||
|
await appsStore.load()
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
message={automationErrorMessage(appId)}
|
message={automationErrorMessage(appId)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
const removeUser = async id => {
|
const removeUser = async id => {
|
||||||
await groups.actions.removeUser(groupId, id)
|
await groups.removeUser(groupId, id)
|
||||||
fetchGroupUsers.refresh()
|
fetchGroupUsers.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,7 @@
|
||||||
passwordModal.show()
|
passwordModal.show()
|
||||||
await fetch.refresh()
|
await fetch.refresh()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
notifications.error("Error creating user")
|
notifications.error("Error creating user")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,71 @@
|
||||||
import { writable } from "svelte/store"
|
|
||||||
import { API } from "@/api"
|
import { API } from "@/api"
|
||||||
import { update } from "lodash"
|
|
||||||
import { licensing } from "."
|
import { licensing } from "."
|
||||||
import { sdk } from "@budibase/shared-core"
|
import { sdk } from "@budibase/shared-core"
|
||||||
import { Constants } from "@budibase/frontend-core"
|
import { Constants } from "@budibase/frontend-core"
|
||||||
|
import {
|
||||||
|
DeleteInviteUsersRequest,
|
||||||
|
InviteUsersRequest,
|
||||||
|
SearchUsersRequest,
|
||||||
|
SearchUsersResponse,
|
||||||
|
UpdateInviteRequest,
|
||||||
|
User,
|
||||||
|
UserIdentifier,
|
||||||
|
UnsavedUser,
|
||||||
|
} from "@budibase/types"
|
||||||
|
import { BudiStore } from "../BudiStore"
|
||||||
|
|
||||||
export function createUsersStore() {
|
interface UserInfo {
|
||||||
const { subscribe, set } = writable({})
|
email: string
|
||||||
|
password: string
|
||||||
|
forceResetPassword?: boolean
|
||||||
|
role: keyof typeof Constants.BudibaseRoles
|
||||||
|
}
|
||||||
|
|
||||||
// opts can contain page and search params
|
type UserState = SearchUsersResponse & SearchUsersRequest
|
||||||
async function search(opts = {}) {
|
|
||||||
|
class UserStore extends BudiStore<UserState> {
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
data: [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async search(opts: SearchUsersRequest = {}) {
|
||||||
const paged = await API.searchUsers(opts)
|
const paged = await API.searchUsers(opts)
|
||||||
set({
|
this.set({
|
||||||
...paged,
|
...paged,
|
||||||
...opts,
|
...opts,
|
||||||
})
|
})
|
||||||
return paged
|
return paged
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get(userId) {
|
async get(userId: string) {
|
||||||
try {
|
try {
|
||||||
return await API.getUser(userId)
|
return await API.getUser(userId)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const fetch = async () => {
|
|
||||||
|
async fetch() {
|
||||||
return await API.getUsers()
|
return await API.getUsers()
|
||||||
}
|
}
|
||||||
|
|
||||||
// One or more users.
|
async onboard(payload: InviteUsersRequest) {
|
||||||
async function onboard(payload) {
|
|
||||||
return await API.onboardUsers(payload)
|
return await API.onboardUsers(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function invite(payload) {
|
async invite(
|
||||||
const users = payload.map(user => {
|
payload: {
|
||||||
|
admin?: boolean
|
||||||
|
builder?: boolean
|
||||||
|
creator?: boolean
|
||||||
|
email: string
|
||||||
|
apps?: any[]
|
||||||
|
groups?: any[]
|
||||||
|
}[]
|
||||||
|
) {
|
||||||
|
const users: InviteUsersRequest = payload.map(user => {
|
||||||
let builder = undefined
|
let builder = undefined
|
||||||
if (user.admin || user.builder) {
|
if (user.admin || user.builder) {
|
||||||
builder = { global: true }
|
builder = { global: true }
|
||||||
|
@ -55,11 +85,16 @@ export function createUsersStore() {
|
||||||
return API.inviteUsers(users)
|
return API.inviteUsers(users)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeInvites(payload) {
|
async removeInvites(payload: DeleteInviteUsersRequest) {
|
||||||
return API.removeUserInvites(payload)
|
return API.removeUserInvites(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function acceptInvite(inviteCode, password, firstName, lastName) {
|
async acceptInvite(
|
||||||
|
inviteCode: string,
|
||||||
|
password: string,
|
||||||
|
firstName: string,
|
||||||
|
lastName?: string
|
||||||
|
) {
|
||||||
return API.acceptInvite({
|
return API.acceptInvite({
|
||||||
inviteCode,
|
inviteCode,
|
||||||
password,
|
password,
|
||||||
|
@ -68,21 +103,25 @@ export function createUsersStore() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchInvite(inviteCode) {
|
async fetchInvite(inviteCode: string) {
|
||||||
return API.getUserInvite(inviteCode)
|
return API.getUserInvite(inviteCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getInvites() {
|
async getInvites() {
|
||||||
return API.getUserInvites()
|
return API.getUserInvites()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateInvite(invite) {
|
async updateInvite(code: string, invite: UpdateInviteRequest) {
|
||||||
return API.updateUserInvite(invite.code, invite)
|
return API.updateUserInvite(code, invite)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function create(data) {
|
async getUserCountByApp(appId: string) {
|
||||||
let mappedUsers = data.users.map(user => {
|
return await API.getUserCountByApp(appId)
|
||||||
const body = {
|
}
|
||||||
|
|
||||||
|
async create(data: { users: UserInfo[]; groups: any[] }) {
|
||||||
|
let mappedUsers: UnsavedUser[] = data.users.map((user: any) => {
|
||||||
|
const body: UnsavedUser = {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
password: user.password,
|
password: user.password,
|
||||||
roles: {},
|
roles: {},
|
||||||
|
@ -92,17 +131,17 @@ export function createUsersStore() {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (user.role) {
|
switch (user.role) {
|
||||||
case "appUser":
|
case Constants.BudibaseRoles.AppUser:
|
||||||
body.builder = { global: false }
|
body.builder = { global: false }
|
||||||
body.admin = { global: false }
|
body.admin = { global: false }
|
||||||
break
|
break
|
||||||
case "developer":
|
case Constants.BudibaseRoles.Developer:
|
||||||
body.builder = { global: true }
|
body.builder = { global: true }
|
||||||
break
|
break
|
||||||
case "creator":
|
case Constants.BudibaseRoles.Creator:
|
||||||
body.builder = { creator: true, global: false }
|
body.builder = { creator: true, global: false }
|
||||||
break
|
break
|
||||||
case "admin":
|
case Constants.BudibaseRoles.Admin:
|
||||||
body.admin = { global: true }
|
body.admin = { global: true }
|
||||||
body.builder = { global: true }
|
body.builder = { global: true }
|
||||||
break
|
break
|
||||||
|
@ -111,43 +150,47 @@ export function createUsersStore() {
|
||||||
return body
|
return body
|
||||||
})
|
})
|
||||||
const response = await API.createUsers(mappedUsers, data.groups)
|
const response = await API.createUsers(mappedUsers, data.groups)
|
||||||
|
licensing.setQuotaUsage()
|
||||||
|
|
||||||
// re-search from first page
|
// re-search from first page
|
||||||
await search()
|
await this.search()
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
async function del(id) {
|
async delete(id: string) {
|
||||||
await API.deleteUser(id)
|
await API.deleteUser(id)
|
||||||
update(users => users.filter(user => user._id !== id))
|
licensing.setQuotaUsage()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getUserCountByApp(appId) {
|
async bulkDelete(users: UserIdentifier[]) {
|
||||||
return await API.getUserCountByApp(appId)
|
const res = API.deleteUsers(users)
|
||||||
|
licensing.setQuotaUsage()
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
async function bulkDelete(users) {
|
async save(user: User) {
|
||||||
return API.deleteUsers(users)
|
const res = await API.saveUser(user)
|
||||||
|
licensing.setQuotaUsage()
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
async function save(user) {
|
async addAppBuilder(userId: string, appId: string) {
|
||||||
return await API.saveUser(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addAppBuilder(userId, appId) {
|
|
||||||
return await API.addAppBuilder(userId, appId)
|
return await API.addAppBuilder(userId, appId)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeAppBuilder(userId, appId) {
|
async removeAppBuilder(userId: string, appId: string) {
|
||||||
return await API.removeAppBuilder(userId, appId)
|
return await API.removeAppBuilder(userId, appId)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAccountHolder() {
|
async getAccountHolder() {
|
||||||
return await API.getAccountHolder()
|
return await API.getAccountHolder()
|
||||||
}
|
}
|
||||||
|
|
||||||
const getUserRole = user => {
|
getUserRole(user?: User & { tenantOwnerEmail?: string }) {
|
||||||
if (user && user.email === user.tenantOwnerEmail) {
|
if (!user) {
|
||||||
|
return Constants.BudibaseRoles.AppUser
|
||||||
|
}
|
||||||
|
if (user.email === user.tenantOwnerEmail) {
|
||||||
return Constants.BudibaseRoles.Owner
|
return Constants.BudibaseRoles.Owner
|
||||||
} else if (sdk.users.isAdmin(user)) {
|
} else if (sdk.users.isAdmin(user)) {
|
||||||
return Constants.BudibaseRoles.Admin
|
return Constants.BudibaseRoles.Admin
|
||||||
|
@ -159,38 +202,6 @@ export function createUsersStore() {
|
||||||
return Constants.BudibaseRoles.AppUser
|
return Constants.BudibaseRoles.AppUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshUsage =
|
|
||||||
fn =>
|
|
||||||
async (...args) => {
|
|
||||||
const response = await fn(...args)
|
|
||||||
await licensing.setQuotaUsage()
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
subscribe,
|
|
||||||
search,
|
|
||||||
get,
|
|
||||||
getUserRole,
|
|
||||||
fetch,
|
|
||||||
invite,
|
|
||||||
onboard,
|
|
||||||
fetchInvite,
|
|
||||||
getInvites,
|
|
||||||
removeInvites,
|
|
||||||
updateInvite,
|
|
||||||
getUserCountByApp,
|
|
||||||
addAppBuilder,
|
|
||||||
removeAppBuilder,
|
|
||||||
// any operation that adds or deletes users
|
|
||||||
acceptInvite,
|
|
||||||
create: refreshUsage(create),
|
|
||||||
save: refreshUsage(save),
|
|
||||||
bulkDelete: refreshUsage(bulkDelete),
|
|
||||||
delete: refreshUsage(del),
|
|
||||||
getAccountHolder,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const users = createUsersStore()
|
export const users = new UserStore()
|
|
@ -21,11 +21,12 @@ import {
|
||||||
SaveUserResponse,
|
SaveUserResponse,
|
||||||
SearchUsersRequest,
|
SearchUsersRequest,
|
||||||
SearchUsersResponse,
|
SearchUsersResponse,
|
||||||
|
UnsavedUser,
|
||||||
UpdateInviteRequest,
|
UpdateInviteRequest,
|
||||||
UpdateInviteResponse,
|
UpdateInviteResponse,
|
||||||
UpdateSelfMetadataRequest,
|
UpdateSelfMetadataRequest,
|
||||||
UpdateSelfMetadataResponse,
|
UpdateSelfMetadataResponse,
|
||||||
User,
|
UserIdentifier,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { BaseAPIClient } from "./types"
|
import { BaseAPIClient } from "./types"
|
||||||
|
|
||||||
|
@ -38,14 +39,9 @@ export interface UserEndpoints {
|
||||||
createAdminUser: (
|
createAdminUser: (
|
||||||
user: CreateAdminUserRequest
|
user: CreateAdminUserRequest
|
||||||
) => Promise<CreateAdminUserResponse>
|
) => Promise<CreateAdminUserResponse>
|
||||||
saveUser: (user: User) => Promise<SaveUserResponse>
|
saveUser: (user: UnsavedUser) => Promise<SaveUserResponse>
|
||||||
deleteUser: (userId: string) => Promise<DeleteUserResponse>
|
deleteUser: (userId: string) => Promise<DeleteUserResponse>
|
||||||
deleteUsers: (
|
deleteUsers: (users: UserIdentifier[]) => Promise<BulkUserDeleted | undefined>
|
||||||
users: Array<{
|
|
||||||
userId: string
|
|
||||||
email: string
|
|
||||||
}>
|
|
||||||
) => Promise<BulkUserDeleted | undefined>
|
|
||||||
onboardUsers: (data: InviteUsersRequest) => Promise<InviteUsersResponse>
|
onboardUsers: (data: InviteUsersRequest) => Promise<InviteUsersResponse>
|
||||||
getUserInvite: (code: string) => Promise<CheckInviteResponse>
|
getUserInvite: (code: string) => Promise<CheckInviteResponse>
|
||||||
getUserInvites: () => Promise<GetUserInvitesResponse>
|
getUserInvites: () => Promise<GetUserInvitesResponse>
|
||||||
|
@ -60,7 +56,7 @@ export interface UserEndpoints {
|
||||||
getAccountHolder: () => Promise<LookupAccountHolderResponse>
|
getAccountHolder: () => Promise<LookupAccountHolderResponse>
|
||||||
searchUsers: (data: SearchUsersRequest) => Promise<SearchUsersResponse>
|
searchUsers: (data: SearchUsersRequest) => Promise<SearchUsersResponse>
|
||||||
createUsers: (
|
createUsers: (
|
||||||
users: User[],
|
users: UnsavedUser[],
|
||||||
groups: any[]
|
groups: any[]
|
||||||
) => Promise<BulkUserCreated | undefined>
|
) => Promise<BulkUserCreated | undefined>
|
||||||
updateUserInvite: (
|
updateUserInvite: (
|
||||||
|
|
|
@ -22,6 +22,8 @@ export interface UserDetails {
|
||||||
password?: string
|
password?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UnsavedUser = Omit<User, "tenantId">
|
||||||
|
|
||||||
export interface BulkUserRequest {
|
export interface BulkUserRequest {
|
||||||
delete?: {
|
delete?: {
|
||||||
users: Array<{
|
users: Array<{
|
||||||
|
@ -31,7 +33,7 @@ export interface BulkUserRequest {
|
||||||
}
|
}
|
||||||
create?: {
|
create?: {
|
||||||
roles?: any[]
|
roles?: any[]
|
||||||
users: User[]
|
users: UnsavedUser[]
|
||||||
groups: any[]
|
groups: any[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +126,7 @@ export interface AcceptUserInviteRequest {
|
||||||
inviteCode: string
|
inviteCode: string
|
||||||
password: string
|
password: string
|
||||||
firstName: string
|
firstName: string
|
||||||
lastName: string
|
lastName?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AcceptUserInviteResponse {
|
export interface AcceptUserInviteResponse {
|
||||||
|
|
|
@ -33,6 +33,7 @@ import {
|
||||||
SaveUserResponse,
|
SaveUserResponse,
|
||||||
SearchUsersRequest,
|
SearchUsersRequest,
|
||||||
SearchUsersResponse,
|
SearchUsersResponse,
|
||||||
|
UnsavedUser,
|
||||||
UpdateInviteRequest,
|
UpdateInviteRequest,
|
||||||
UpdateInviteResponse,
|
UpdateInviteResponse,
|
||||||
User,
|
User,
|
||||||
|
@ -49,6 +50,7 @@ import {
|
||||||
tenancy,
|
tenancy,
|
||||||
db,
|
db,
|
||||||
locks,
|
locks,
|
||||||
|
context,
|
||||||
} from "@budibase/backend-core"
|
} from "@budibase/backend-core"
|
||||||
import { checkAnyUserExists } from "../../../utilities/users"
|
import { checkAnyUserExists } from "../../../utilities/users"
|
||||||
import { isEmailConfigured } from "../../../utilities/email"
|
import { isEmailConfigured } from "../../../utilities/email"
|
||||||
|
@ -66,10 +68,11 @@ const generatePassword = (length: number) => {
|
||||||
.slice(0, length)
|
.slice(0, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const save = async (ctx: UserCtx<User, SaveUserResponse>) => {
|
export const save = async (ctx: UserCtx<UnsavedUser, SaveUserResponse>) => {
|
||||||
try {
|
try {
|
||||||
const currentUserId = ctx.user?._id
|
const currentUserId = ctx.user?._id
|
||||||
const requestUser = ctx.request.body
|
const tenantId = context.getTenantId()
|
||||||
|
const requestUser: User = { ...ctx.request.body, tenantId }
|
||||||
|
|
||||||
// Do not allow the account holder role to be changed
|
// Do not allow the account holder role to be changed
|
||||||
if (
|
if (
|
||||||
|
@ -151,7 +154,12 @@ export const bulkUpdate = async (
|
||||||
let created, deleted
|
let created, deleted
|
||||||
try {
|
try {
|
||||||
if (input.create) {
|
if (input.create) {
|
||||||
created = await bulkCreate(input.create.users, input.create.groups)
|
const tenantId = context.getTenantId()
|
||||||
|
const users: User[] = input.create.users.map(user => ({
|
||||||
|
...user,
|
||||||
|
tenantId,
|
||||||
|
}))
|
||||||
|
created = await bulkCreate(users, input.create.groups)
|
||||||
}
|
}
|
||||||
if (input.delete) {
|
if (input.delete) {
|
||||||
deleted = await bulkDelete(input.delete.users, currentUserId)
|
deleted = await bulkDelete(input.delete.users, currentUserId)
|
||||||
|
|
Loading…
Reference in New Issue