Merge branch 'master' of github.com:Budibase/budibase into fix/lockdown-admin
This commit is contained in:
commit
348c61a8c5
|
@ -12,15 +12,7 @@
|
|||
export let size = "M"
|
||||
export let url = ""
|
||||
export let disabled = false
|
||||
export let name = "John Doe"
|
||||
|
||||
function getInitials(name) {
|
||||
let parts = name.split(" ")
|
||||
if (parts.length > 0) {
|
||||
return parts.map(name => name[0]).join("")
|
||||
}
|
||||
return name
|
||||
}
|
||||
export let initials = "JD"
|
||||
</script>
|
||||
|
||||
{#if url}
|
||||
|
@ -38,7 +30,7 @@
|
|||
size
|
||||
)}); font-size: calc(var({sizes.get(size)}) / 2)"
|
||||
>
|
||||
{getInitials(name)}
|
||||
{initials || ""}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
@ -52,5 +44,6 @@
|
|||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
on:blur
|
||||
on:focus
|
||||
on:input
|
||||
on:keyup
|
||||
on:blur={onBlur}
|
||||
on:focus={onFocus}
|
||||
on:input={onInput}
|
||||
|
|
|
@ -34,5 +34,6 @@
|
|||
on:input
|
||||
on:blur
|
||||
on:focus
|
||||
on:keyup
|
||||
/>
|
||||
</Field>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
const updatePassword = async () => {
|
||||
try {
|
||||
await auth.updateSelf({ ...$auth.user, password })
|
||||
await auth.updateSelf({ password })
|
||||
notifications.success("Password changed successfully")
|
||||
} catch (error) {
|
||||
notifications.error("Failed to update password")
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
const updateInfo = async () => {
|
||||
try {
|
||||
await auth.updateSelf({ ...$auth.user, ...$values })
|
||||
await auth.updateSelf($values)
|
||||
notifications.success("Information updated successfully")
|
||||
} catch (error) {
|
||||
notifications.error("Failed to update information")
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
import { goto } from "@roxi/routify"
|
||||
import api from "builderStore/api"
|
||||
import { admin, organisation } from "stores/portal"
|
||||
import PasswordRepeatInput from "components/common/users/PasswordRepeatInput.svelte"
|
||||
|
||||
let adminUser = {}
|
||||
let error
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
|
@ -42,13 +44,11 @@
|
|||
</Layout>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Input label="Email" bind:value={adminUser.email} />
|
||||
<Input
|
||||
label="Password"
|
||||
type="password"
|
||||
bind:value={adminUser.password}
|
||||
/>
|
||||
<PasswordRepeatInput bind:password={adminUser.password} bind:error />
|
||||
</Layout>
|
||||
<Button cta on:click={save}>Create super admin user</Button>
|
||||
<Button cta disabled={error} on:click={save}>
|
||||
Create super admin user
|
||||
</Button>
|
||||
</Layout>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
</Layout>
|
||||
<ActionMenu align="right">
|
||||
<div slot="control" class="avatar">
|
||||
<Avatar size="M" name="John Doe" />
|
||||
<Avatar size="M" initials={$auth.initials} />
|
||||
<Icon size="XL" name="ChevronDown" />
|
||||
</div>
|
||||
<MenuItem icon="UserEdit" on:click={() => userInfoModal.show()}>
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { ActionButton } from "@budibase/bbui"
|
||||
import GoogleLogo from "/assets/google-logo.png"
|
||||
import { admin } from "stores/portal"
|
||||
|
||||
let show = false
|
||||
|
||||
$: show = $admin.checklist?.oauth
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
<ActionButton>
|
||||
<a target="_blank" href="/api/admin/auth/google">
|
||||
<div class="inner">
|
||||
|
@ -11,14 +18,9 @@
|
|||
</div>
|
||||
</a>
|
||||
</ActionButton>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.outer {
|
||||
border: 1px solid #494949;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
background-color: var(--background-alt);
|
||||
}
|
||||
.inner {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
@ -38,8 +38,13 @@
|
|||
notifications.error("Invalid credentials")
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(evt) {
|
||||
if (evt.key === "Enter") login()
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
<div class="login">
|
||||
<div class="main">
|
||||
<Layout>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
try {
|
||||
if (forceResetPassword) {
|
||||
await auth.updateSelf({
|
||||
...$auth.user,
|
||||
password,
|
||||
forceResetPassword: false,
|
||||
})
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import {
|
||||
Icon,
|
||||
Avatar,
|
||||
Search,
|
||||
Layout,
|
||||
SideNavigation as Navigation,
|
||||
SideNavigationItem as Item,
|
||||
|
@ -77,7 +76,7 @@
|
|||
<div />
|
||||
<ActionMenu align="right">
|
||||
<div slot="control" class="avatar">
|
||||
<Avatar size="M" name="John Doe" />
|
||||
<Avatar size="M" initials={$auth.initials} />
|
||||
<Icon size="XL" name="ChevronDown" />
|
||||
</div>
|
||||
<MenuItem icon="UserEdit" on:click={() => userInfoModal.show()}>
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
const enrichedApps = apps.map(app => ({
|
||||
...app,
|
||||
deployed: app.status === AppStatus.DEPLOYED,
|
||||
lockedYou: app.lockedBy?.email === user.email,
|
||||
lockedOther: app.lockedBy && app.lockedBy.email !== user.email,
|
||||
lockedYou: app.lockedBy && app.lockedBy.email === user?.email,
|
||||
lockedOther: app.lockedBy && app.lockedBy.email !== user?.email,
|
||||
}))
|
||||
if (sortBy === "status") {
|
||||
return enrichedApps.sort((a, b) => {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
Button,
|
||||
Heading,
|
||||
Divider,
|
||||
Page,
|
||||
Label,
|
||||
notifications,
|
||||
Layout,
|
||||
|
@ -23,6 +22,13 @@
|
|||
const ConfigFields = {
|
||||
Google: ["clientID", "clientSecret", "callbackURL"],
|
||||
}
|
||||
const ConfigLabels = {
|
||||
Google: {
|
||||
clientID: "Client ID",
|
||||
clientSecret: "Client secret",
|
||||
callbackURL: "Callback URL",
|
||||
},
|
||||
}
|
||||
|
||||
let google
|
||||
|
||||
|
@ -85,7 +91,7 @@
|
|||
<Layout gap="XS" noPadding>
|
||||
{#each ConfigFields.Google as field}
|
||||
<div class="form-row">
|
||||
<Label size="L">{field}</Label>
|
||||
<Label size="L">{ConfigLabels.Google[field]}</Label>
|
||||
<Input bind:value={google.config[field]} />
|
||||
</div>
|
||||
{/each}
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
<Heading>User: {$userFetch?.data?.email}</Heading>
|
||||
<Body>
|
||||
Change user settings and update their app roles. Also contains the ability
|
||||
to delete the user as well as force reset their password..
|
||||
to delete the user as well as force reset their password.
|
||||
</Body>
|
||||
</Layout>
|
||||
<Divider size="S" />
|
||||
|
@ -118,7 +118,7 @@
|
|||
<!-- don't let a user remove the privileges that let them be here -->
|
||||
{#if userId !== $auth.user._id}
|
||||
<div class="field">
|
||||
<Label size="L">Development access?</Label>
|
||||
<Label size="L">Development access</Label>
|
||||
<Toggle
|
||||
text=""
|
||||
value={$userFetch?.data?.builder?.global}
|
||||
|
@ -127,7 +127,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<Label size="L">Administration access?</Label>
|
||||
<Label size="L">Administration access</Label>
|
||||
<Toggle
|
||||
text=""
|
||||
value={$userFetch?.data?.admin?.global}
|
||||
|
|
|
@ -9,9 +9,10 @@
|
|||
$: leftover = roles.length - tags.length
|
||||
</script>
|
||||
|
||||
<div class="tag-renderer">
|
||||
<Tags>
|
||||
{#each tags as tag}
|
||||
<Tag disabled>
|
||||
<Tag>
|
||||
{tag}
|
||||
</Tag>
|
||||
{/each}
|
||||
|
@ -19,3 +20,15 @@
|
|||
<Tag>+{leftover} more</Tag>
|
||||
{/if}
|
||||
</Tags>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tag-renderer :global(.spectrum-Tags-item:hover) {
|
||||
color: var(--spectrum-alias-label-text-color);
|
||||
border-color: var(--spectrum-alias-border-color-darker-default);
|
||||
cursor: pointer;
|
||||
}
|
||||
.tag-renderer :global(.spectrum-Tags-itemLabel) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -53,9 +53,8 @@
|
|||
<Layout gap="XS" noPadding>
|
||||
<Heading>Users</Heading>
|
||||
<Body>
|
||||
Users are the common denominator in Budibase. Each user is assigned to a
|
||||
group that contains apps and permissions. In this section, you can add
|
||||
users, or edit and delete an existing user.
|
||||
Each user is assigned to a group that contains apps and permissions. In
|
||||
this section, you can add users, or edit and delete an existing user.
|
||||
</Body>
|
||||
</Layout>
|
||||
<Divider size="S" />
|
||||
|
|
|
@ -1,25 +1,42 @@
|
|||
import { writable } from "svelte/store"
|
||||
import { derived, writable, get } from "svelte/store"
|
||||
import api from "../../builderStore/api"
|
||||
|
||||
export function createAuthStore() {
|
||||
const store = writable({ user: null })
|
||||
const user = writable(null)
|
||||
const store = derived(user, $user => {
|
||||
let initials = null
|
||||
if ($user) {
|
||||
if ($user.firstName) {
|
||||
initials = $user.firstName[0]
|
||||
if ($user.lastName) {
|
||||
initials += $user.lastName[0]
|
||||
}
|
||||
} else {
|
||||
initials = $user.email[0]
|
||||
}
|
||||
}
|
||||
return {
|
||||
user: $user,
|
||||
initials,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
subscribe: store.subscribe,
|
||||
checkAuth: async () => {
|
||||
const response = await api.get("/api/admin/users/self")
|
||||
if (response.status !== 200) {
|
||||
store.update(state => ({ ...state, user: null }))
|
||||
user.set(null)
|
||||
} else {
|
||||
const user = await response.json()
|
||||
store.update(state => ({ ...state, user }))
|
||||
const json = await response.json()
|
||||
user.set(json)
|
||||
}
|
||||
},
|
||||
login: async creds => {
|
||||
const response = await api.post(`/api/admin/auth`, creds)
|
||||
const json = await response.json()
|
||||
if (response.status === 200) {
|
||||
store.update(state => ({ ...state, user: json.user }))
|
||||
user.set(json.user)
|
||||
} else {
|
||||
throw "Invalid credentials"
|
||||
}
|
||||
|
@ -31,12 +48,13 @@ export function createAuthStore() {
|
|||
throw "Unable to create logout"
|
||||
}
|
||||
await response.json()
|
||||
store.update(state => ({ ...state, user: null }))
|
||||
user.set(null)
|
||||
},
|
||||
updateSelf: async user => {
|
||||
const response = await api.post("/api/admin/users/self", user)
|
||||
updateSelf: async fields => {
|
||||
const newUser = { ...get(user), ...fields }
|
||||
const response = await api.post("/api/admin/users/self", newUser)
|
||||
if (response.status === 200) {
|
||||
store.update(state => ({ ...state, user: { ...state.user, ...user } }))
|
||||
user.set(newUser)
|
||||
} else {
|
||||
throw "Unable to update user details"
|
||||
}
|
||||
|
|
|
@ -168,6 +168,11 @@ exports.configChecklist = async function (ctx) {
|
|||
type: Configs.SMTP,
|
||||
})
|
||||
|
||||
// They have set up Google Auth
|
||||
const oauthConfig = await getScopedFullConfig(db, {
|
||||
type: Configs.GOOGLE,
|
||||
})
|
||||
|
||||
// They have set up an admin user
|
||||
const users = await db.allDocs(
|
||||
getGlobalUserParams(null, {
|
||||
|
@ -180,6 +185,7 @@ exports.configChecklist = async function (ctx) {
|
|||
apps: appDbNames.length,
|
||||
smtp: !!smtpConfig,
|
||||
adminUser,
|
||||
oauth: !!oauthConfig,
|
||||
}
|
||||
} catch (err) {
|
||||
ctx.throw(err.status, err)
|
||||
|
|
Loading…
Reference in New Issue