Merge pull request #11036 from Budibase/merge-master

Merge master
This commit is contained in:
deanhannigan 2023-06-27 10:31:10 +01:00 committed by GitHub
commit e26524a6b9
8 changed files with 115 additions and 42 deletions

View File

@ -1,9 +1,7 @@
{ {
"version": "2.7.34-alpha.10", "version": "2.7.35",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": ["packages/*"],
"packages/*"
],
"useNx": true, "useNx": true,
"command": { "command": {
"publish": { "publish": {

View File

@ -5,6 +5,7 @@ import {
GoogleInnerConfig, GoogleInnerConfig,
OIDCConfig, OIDCConfig,
OIDCInnerConfig, OIDCInnerConfig,
OIDCLogosConfig,
SCIMConfig, SCIMConfig,
SCIMInnerConfig, SCIMInnerConfig,
SettingsConfig, SettingsConfig,
@ -191,6 +192,10 @@ export function getDefaultGoogleConfig(): GoogleInnerConfig | undefined {
// OIDC // OIDC
export async function getOIDCLogosDoc(): Promise<OIDCLogosConfig | undefined> {
return getConfig<OIDCLogosConfig>(ConfigType.OIDC_LOGOS)
}
async function getOIDCConfigDoc(): Promise<OIDCConfig | undefined> { async function getOIDCConfigDoc(): Promise<OIDCConfig | undefined> {
return getConfig<OIDCConfig>(ConfigType.OIDC) return getConfig<OIDCConfig>(ConfigType.OIDC)
} }

View File

@ -99,9 +99,15 @@
bind:this={button} bind:this={button}
> >
{#if fieldIcon} {#if fieldIcon}
<span class="option-extra icon"> {#if !useOptionIconImage}
<Icon size="S" name={fieldIcon} /> <span class="option-extra icon">
</span> <Icon size="S" name={fieldIcon} />
</span>
{:else}
<span class="option-extra icon field-icon">
<img src={fieldIcon} alt="icon" width="15" height="15" />
</span>
{/if}
{/if} {/if}
{#if fieldColour} {#if fieldColour}
<span class="option-extra"> <span class="option-extra">
@ -311,4 +317,8 @@
max-width: 170px; max-width: 170px;
font-size: 12px; font-size: 12px;
} }
.option-extra.icon.field-icon {
display: flex;
}
</style> </style>

View File

@ -40,6 +40,8 @@
let userOnboardResponse = null let userOnboardResponse = null
let userLimitReachedModal let userLimitReachedModal
let inviteFailureResponse = ""
$: queryIsEmail = emailValidator(query) === true $: queryIsEmail = emailValidator(query) === true
$: prodAppId = apps.getProdAppID($store.appId) $: prodAppId = apps.getProdAppID($store.appId)
$: promptInvite = showInvite( $: promptInvite = showInvite(
@ -308,19 +310,6 @@
let userInviteResponse let userInviteResponse
try { try {
userInviteResponse = await users.onboard(payload) userInviteResponse = await users.onboard(payload)
const newUser = userInviteResponse?.successful.find(
user => user.email === newUserEmail
)
if (newUser) {
notifications.success(
userInviteResponse.created
? "User created successfully"
: "User invite successful"
)
} else {
throw new Error("User invite failed")
}
} catch (error) { } catch (error) {
console.error(error.message) console.error(error.message)
notifications.error("Error inviting user") notifications.error("Error inviting user")
@ -331,12 +320,31 @@
const onInviteUser = async () => { const onInviteUser = async () => {
userOnboardResponse = await inviteUser() userOnboardResponse = await inviteUser()
const originalQuery = query + ""
query = null
const userInviteSuccess = userOnboardResponse?.successful const newUser = userOnboardResponse?.successful.find(
if (userInviteSuccess && userInviteSuccess[0].email === query) { user => user.email === originalQuery
query = null )
query = userInviteSuccess[0].email if (newUser) {
query = originalQuery
notifications.success(
userOnboardResponse.created
? "User created successfully"
: "User invite successful"
)
} else {
const failedUser = userOnboardResponse?.unsuccessful.find(
user => user.email === originalQuery
)
inviteFailureResponse =
failedUser?.reason === "Unavailable"
? "Email already in use. Please use a different email."
: failedUser?.reason
notifications.error(inviteFailureResponse)
} }
userOnboardResponse = null
} }
const onUpdateUserInvite = async (invite, role) => { const onUpdateUserInvite = async (invite, role) => {

View File

@ -29,14 +29,13 @@
} }
}) })
$: src = !$oidc.logo $: oidcLogoImageURL = preDefinedIcons[$oidc.logo] ?? $oidc.logo
? OidcLogo $: logoSrc = oidcLogoImageURL ?? OidcLogo
: preDefinedIcons[$oidc.logo] || `/global/logos_oidc/${$oidc.logo}`
</script> </script>
{#if show} {#if show}
<FancyButton <FancyButton
icon={src} icon={logoSrc}
on:click={() => { on:click={() => {
const url = `/api/global/auth/${$auth.tenantId}/oidc/configs/${$oidc.uuid}` const url = `/api/global/auth/${$auth.tenantId}/oidc/configs/${$oidc.uuid}`
if (samePage) { if (samePage) {

View File

@ -382,18 +382,26 @@ class MongoIntegration implements IntegrationBase {
return this.client.connect() return this.client.connect()
} }
createObjectIds(json: any) { matchId(value?: string) {
return value?.match(/(?<=objectid\(['"]).*(?=['"]\))/gi)?.[0]
}
hasObjectId(value?: any): boolean {
return (
typeof value === "string" && value.toLowerCase().startsWith("objectid")
)
}
createObjectIds(json: any): any {
const self = this const self = this
function interpolateObjectIds(json: any) { function interpolateObjectIds(json: any) {
for (let field of Object.keys(json || {})) { for (let field of Object.keys(json || {})) {
if (json[field] instanceof Object) { if (json[field] instanceof Object) {
json[field] = self.createObjectIds(json[field]) json[field] = self.createObjectIds(json[field])
} }
if ( if (self.hasObjectId(json[field])) {
typeof json[field] === "string" && const id = self.matchId(json[field])
json[field].toLowerCase().startsWith("objectid")
) {
const id = json[field].match(/(?<=objectid\(['"]).*(?=['"]\))/gi)?.[0]
if (id) { if (id) {
json[field] = ObjectId.createFromHexString(id) json[field] = ObjectId.createFromHexString(id)
} }
@ -404,7 +412,14 @@ class MongoIntegration implements IntegrationBase {
if (Array.isArray(json)) { if (Array.isArray(json)) {
for (let i = 0; i < json.length; i++) { for (let i = 0; i < json.length; i++) {
json[i] = interpolateObjectIds(json[i]) if (self.hasObjectId(json[i])) {
const id = self.matchId(json[i])
if (id) {
json[i] = ObjectId.createFromHexString(id)
}
} else {
json[i] = interpolateObjectIds(json[i])
}
} }
return json return json
} }

View File

@ -79,6 +79,12 @@ export interface OIDCConfigs {
configs: OIDCInnerConfig[] configs: OIDCInnerConfig[]
} }
export interface OIDCLogosInnerConfig {
[key: string]: string
}
export interface OIDCLogosConfig extends Config<OIDCLogosInnerConfig> {}
export interface OIDCInnerConfig { export interface OIDCInnerConfig {
configUrl: string configUrl: string
clientID: string clientID: string

View File

@ -28,6 +28,7 @@ import {
SSOConfig, SSOConfig,
SSOConfigType, SSOConfigType,
UserCtx, UserCtx,
OIDCLogosConfig,
} from "@budibase/types" } from "@budibase/types"
import * as pro from "@budibase/pro" import * as pro from "@budibase/pro"
@ -280,13 +281,39 @@ export async function save(ctx: UserCtx<Config>) {
} }
} }
function enrichOIDCLogos(oidcLogos: OIDCLogosConfig) {
if (!oidcLogos) {
return
}
oidcLogos.config = Object.keys(oidcLogos.config || {}).reduce(
(acc: any, key: string) => {
if (!key.endsWith("Etag")) {
const etag = oidcLogos.config[`${key}Etag`]
const objectStoreUrl = objectStore.getGlobalFileUrl(
oidcLogos.type,
key,
etag
)
acc[key] = objectStoreUrl
} else {
acc[key] = oidcLogos.config[key]
}
return acc
},
{}
)
}
export async function find(ctx: UserCtx) { export async function find(ctx: UserCtx) {
try { try {
// Find the config with the most granular scope based on context // Find the config with the most granular scope based on context
const type = ctx.params.type const type = ctx.params.type
const scopedConfig = await configs.getConfig(type) let scopedConfig = await configs.getConfig(type)
if (scopedConfig) { if (scopedConfig) {
if (type === ConfigType.OIDC_LOGOS) {
enrichOIDCLogos(scopedConfig)
}
ctx.body = scopedConfig ctx.body = scopedConfig
} else { } else {
// don't throw an error, there simply is nothing to return // don't throw an error, there simply is nothing to return
@ -300,16 +327,21 @@ export async function find(ctx: UserCtx) {
export async function publicOidc(ctx: Ctx<void, GetPublicOIDCConfigResponse>) { export async function publicOidc(ctx: Ctx<void, GetPublicOIDCConfigResponse>) {
try { try {
// Find the config with the most granular scope based on context // Find the config with the most granular scope based on context
const config = await configs.getOIDCConfig() const oidcConfig = await configs.getOIDCConfig()
const oidcCustomLogos = await configs.getOIDCLogosDoc()
if (!config) { if (oidcCustomLogos) {
enrichOIDCLogos(oidcCustomLogos)
}
if (!oidcConfig) {
ctx.body = [] ctx.body = []
} else { } else {
ctx.body = [ ctx.body = [
{ {
logo: config.logo, logo: oidcCustomLogos?.config[oidcConfig.logo] ?? oidcConfig.logo,
name: config.name, name: oidcConfig.name,
uuid: config.uuid, uuid: oidcConfig.uuid,
}, },
] ]
} }