diff --git a/packages/bbui/src/Layout/Layout.svelte b/packages/bbui/src/Layout/Layout.svelte index 504db41133..86fd844ca1 100644 --- a/packages/bbui/src/Layout/Layout.svelte +++ b/packages/bbui/src/Layout/Layout.svelte @@ -22,6 +22,7 @@ .container { display: grid; grid-template-columns: 1fr; + position: relative; } .paddingX-S { padding-left: var(--spacing-s); diff --git a/packages/bbui/src/Typography/Body.svelte b/packages/bbui/src/Typography/Body.svelte index d2c55da04f..9a1fe266fc 100644 --- a/packages/bbui/src/Typography/Body.svelte +++ b/packages/bbui/src/Typography/Body.svelte @@ -3,27 +3,17 @@ export let size = "M" export let serif = false - export let noPadding = false - export let weight = 400 - export let textAlign = "left" + export let weight = null + export let textAlign = null

- - diff --git a/packages/bbui/src/Typography/Heading.svelte b/packages/bbui/src/Typography/Heading.svelte index 4d0814a22d..72f3ba2a8f 100644 --- a/packages/bbui/src/Typography/Heading.svelte +++ b/packages/bbui/src/Typography/Heading.svelte @@ -3,12 +3,14 @@ // Sizes export let size = "M" - export let textAlign = "left" + export let textAlign export let noPadding = false -

+

diff --git a/packages/builder/src/components/backend/DataTable/Table.svelte b/packages/builder/src/components/backend/DataTable/Table.svelte index 6555197cb2..40a5d1dbac 100644 --- a/packages/builder/src/components/backend/DataTable/Table.svelte +++ b/packages/builder/src/components/backend/DataTable/Table.svelte @@ -47,6 +47,8 @@ }) schema.email.displayName = "Email" schema.roleId.displayName = "Role" + schema.firstName.displayName = "First Name" + schema.lastName.displayName = "Last Name" if (schema.status) { schema.status.displayName = "Status" } diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte index 11210db49f..bf1030dc2c 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditUser.svelte @@ -32,6 +32,8 @@ delete customSchema["email"] delete customSchema["roleId"] delete customSchema["status"] + delete customSchema["firstName"] + delete customSchema["lastName"] return Object.entries(customSchema) } @@ -87,6 +89,14 @@ meta={{ name: "password", type: "password" }} bind:value={row.password} /> + + + + diff --git a/packages/builder/src/components/login/ForgotForm.svelte b/packages/builder/src/components/login/ForgotForm.svelte index 1aa7437767..6eec3b4208 100644 --- a/packages/builder/src/components/login/ForgotForm.svelte +++ b/packages/builder/src/components/login/ForgotForm.svelte @@ -1,11 +1,25 @@ diff --git a/packages/builder/src/components/login/GoogleButton.svelte b/packages/builder/src/components/login/GoogleButton.svelte index 9f154df059..b68ad85752 100644 --- a/packages/builder/src/components/login/GoogleButton.svelte +++ b/packages/builder/src/components/login/GoogleButton.svelte @@ -1,17 +1,16 @@ - - + + diff --git a/packages/builder/src/components/login/LoginForm.svelte b/packages/builder/src/components/login/LoginForm.svelte index bc32c74689..36b1764241 100644 --- a/packages/builder/src/components/login/LoginForm.svelte +++ b/packages/builder/src/components/login/LoginForm.svelte @@ -40,8 +40,8 @@ Sign in to Budibase + - Sign in with email - + $goto("./forgot")}> Forgot password? diff --git a/packages/builder/src/components/login/ResetForm.svelte b/packages/builder/src/components/login/ResetForm.svelte index 1d273a95d2..8f82c23193 100644 --- a/packages/builder/src/components/login/ResetForm.svelte +++ b/packages/builder/src/components/login/ResetForm.svelte @@ -1,12 +1,23 @@ diff --git a/packages/builder/src/components/start/AppCard.svelte b/packages/builder/src/components/start/AppCard.svelte index 1d444b2afb..2aa5e6650d 100644 --- a/packages/builder/src/components/start/AppCard.svelte +++ b/packages/builder/src/components/start/AppCard.svelte @@ -48,7 +48,7 @@
- + Edited {Math.floor(1 + Math.random() * 10)} months ago {#if app.lockedBy} diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index 589e0af799..0b9ff98aa5 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -22,7 +22,13 @@ // Redirect to log in at any time if the user isn't authenticated $: { - if (loaded && hasAdminUser && !$auth.user && !$isActive("./auth")) { + if ( + loaded && + hasAdminUser && + !$auth.user && + !$isActive("./auth") && + !$isActive("./invite") + ) { $redirect("./auth/login") } } diff --git a/packages/builder/src/pages/builder/admin/index.svelte b/packages/builder/src/pages/builder/admin/index.svelte index 1b3be282ab..77a1b43c57 100644 --- a/packages/builder/src/pages/builder/admin/index.svelte +++ b/packages/builder/src/pages/builder/admin/index.svelte @@ -36,7 +36,7 @@ Create an admin user - + The admin user has access to everything in Budibase. diff --git a/packages/builder/src/pages/builder/apps/_components/UpdateUserInfoModal.svelte b/packages/builder/src/pages/builder/apps/_components/UpdateUserInfoModal.svelte new file mode 100644 index 0000000000..e54c3c719f --- /dev/null +++ b/packages/builder/src/pages/builder/apps/_components/UpdateUserInfoModal.svelte @@ -0,0 +1,40 @@ + + + + + Personalise the platform by adding your first name and last name. + + + + diff --git a/packages/builder/src/pages/builder/apps/index.svelte b/packages/builder/src/pages/builder/apps/index.svelte index 3b383bc1ba..7d9c8b93b4 100644 --- a/packages/builder/src/pages/builder/apps/index.svelte +++ b/packages/builder/src/pages/builder/apps/index.svelte @@ -10,6 +10,7 @@ Page, Icon, Body, + Modal, } from "@budibase/bbui" import { onMount } from "svelte" import { apps, organisation } from "stores/portal" @@ -17,8 +18,11 @@ import { goto } from "@roxi/routify" import { AppStatus } from "constants" import { gradient } from "actions" + import UpdateUserInfoModal from "./_components/UpdateUserInfoModal.svelte" let loaded = false + let userInfoModal + let userPasswordModal onMount(async () => { await organisation.init() @@ -35,8 +39,10 @@
- Hey {$auth.user.email} - + + Hey {$auth.user.firstName || $auth.user.email} + + Welcome to the {$organisation.company} portal. Below you'll find the list of apps that you have access to, as well as company news and the employee handbook. @@ -47,7 +53,9 @@
- Update user information + userInfoModal.show()}> + Update user information + Update password
- GROUP + GROUP {#if $auth.user?.builder?.global} {/if} @@ -76,7 +84,7 @@
{app.name} - + Edited {Math.round(Math.random() * 10 + 1)} months ago
@@ -89,6 +97,9 @@
+ + + {/if} diff --git a/packages/builder/src/pages/builder/invite/index.svelte b/packages/builder/src/pages/builder/invite/index.svelte index 1b6b06b648..65b20f8a9d 100644 --- a/packages/builder/src/pages/builder/invite/index.svelte +++ b/packages/builder/src/pages/builder/invite/index.svelte @@ -1,29 +1,15 @@ - - -
- OAuth - - Every budibase app comes with basic authentication (email/password) - included. You can add additional authentication methods from the options - below. - -
+ + + OAuth + + Every budibase app comes with basic authentication (email/password) + included. You can add additional authentication methods from the options + below. + + + {#if google} - {#if google} -
- - - - Google - - - - To allow users to authenticate using their Google accounts, fill out - the fields below. - -
- + + + + + Google + + + + To allow users to authenticate using their Google accounts, fill out the + fields below. + + + {#each ConfigFields.Google as field}
{/each} -
- -
- - {/if} -
-
+
+
+ +
+ {/if} + diff --git a/packages/builder/src/pages/builder/portal/manage/oauth/_logos/Google.svelte b/packages/builder/src/pages/builder/portal/manage/oauth/_logos/Google.svelte deleted file mode 100644 index 5686e50abc..0000000000 --- a/packages/builder/src/pages/builder/portal/manage/oauth/_logos/Google.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - diff --git a/packages/builder/src/pages/builder/portal/manage/oauth/index.svelte b/packages/builder/src/pages/builder/portal/manage/oauth/index.svelte deleted file mode 100644 index f9d2c49cfd..0000000000 --- a/packages/builder/src/pages/builder/portal/manage/oauth/index.svelte +++ /dev/null @@ -1,115 +0,0 @@ - - - -
- OAuth - - Every budibase app comes with basic authentication (email/password) - included. You can add additional authentication methods from the options - below. - -
- - {#if google} -
- - - - - Google - - - {#each ConfigFields.Google as field} -
- - -
- {/each} -
- -
- - {/if} -
- - diff --git a/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte b/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte index b8c55d6aca..a8d9a7c712 100644 --- a/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/manage/users/[userId].svelte @@ -51,45 +51,55 @@ } async function openUpdateRolesModal({ detail }) { - console.log(detail) selectedApp = detail editRolesModal.show() } - -
- $goto("./")} quiet size="S" icon="BackAndroid" - >Back to users -
-
- - User: {$roleFetch?.data?.email} - Lorem ipsum dolor sit amet consectetur adipisicing elit. Debitis porro - ut nesciunt ipsam perspiciatis aliquam et hic minus alias beatae. Odit - veritatis quos quas laborum magnam tenetur perspiciatis ex hic. - - -
+ + +
+ $goto("./")} + quiet + size="S" + icon="BackAndroid" + > + Back to users + +
+ User: {$roleFetch?.data?.email} + + Lorem ipsum dolor sit amet consectetur adipisicing elit. Debitis porro ut + nesciunt ipsam perspiciatis aliquam et hic minus alias beatae. Odit + veritatis quos quas laborum magnam tenetur perspiciatis ex hic. + +
-
+ General
+
+ + +
+
+ + +
- Regenerate password + + Regenerate password +
-
+
-
+ Configure roles - + -
- Delete user - Deleting a user completely removes them from your account. -
- -
+ + Delete user + Deleting a user completely removes them from your account. + +
+
@@ -122,10 +130,9 @@ cancelText="Cancel" showCloseIcon={false} > - Are you sure you want to delete {$roleFetch?.data?.email} + + Are you sure you want to delete {$roleFetch?.data?.email} + @@ -140,26 +147,12 @@ .fields { display: grid; grid-gap: var(--spacing-m); - margin-top: var(--spacing-xl); } .field { display: grid; grid-template-columns: 32% 1fr; align-items: center; } - .heading { - margin-bottom: var(--spacing-xl); - } - .general { - position: relative; - margin: var(--spacing-xl) 0; - } - .roles { - margin: var(--spacing-xl) 0; - } - .delete { - margin-top: var(--spacing-xl); - } .regenerate { position: absolute; top: 0; diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/AddUserModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/AddUserModal.svelte index 8646da9c06..b60f15d976 100644 --- a/packages/builder/src/pages/builder/portal/manage/users/_components/AddUserModal.svelte +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/AddUserModal.svelte @@ -30,18 +30,18 @@ - If you have SMTP configured and an email for the new user, you can use the + + If you have SMTP configured and an email for the new user, you can use the automated email onboarding flow. Otherwise, use our basic onboarding process - with autogenerated passwords. + with autogenerated passwords. + role != null) ?? [] + $: tags = roles.slice(0, displayLimit) + $: leftover = roles.length - tags.length diff --git a/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte b/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte index 4e47d96552..d515c30d4b 100644 --- a/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte +++ b/packages/builder/src/pages/builder/portal/manage/users/_components/UpdateRolesModal.svelte @@ -1,7 +1,6 @@ -
+ Users - Users are the common denominator in Budibase. Each user is assigned to a + + 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. -
+ users, or edit and delete an existing user. + +
- -
- Users -
- - -
-
+ +
+ Users
+
+ + +
$goto(`./${detail._id}`)} {schema} @@ -75,31 +74,28 @@ allowSelectRows={false} customRenderers={[{ column: "group", component: TagsRenderer }]} /> - + - + + + diff --git a/packages/builder/src/pages/builder/portal/oauth/_logos/Google.svelte b/packages/builder/src/pages/builder/portal/oauth/_logos/Google.svelte deleted file mode 100644 index 5686e50abc..0000000000 --- a/packages/builder/src/pages/builder/portal/oauth/_logos/Google.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - diff --git a/packages/builder/src/pages/builder/portal/oauth/index.svelte b/packages/builder/src/pages/builder/portal/oauth/index.svelte deleted file mode 100644 index f8d9b43dec..0000000000 --- a/packages/builder/src/pages/builder/portal/oauth/index.svelte +++ /dev/null @@ -1,114 +0,0 @@ - - - - -
- OAuth - - Every budibase app comes with basic authentication (email/password) - included. You can add additional authentication methods from the options - below. - -
- - {#if google} -
- - - - Google - - - - To allow users to authenticate using their Google accounts, fill out - the fields below. - -
- - {#each ConfigFields.Google as field} -
- - -
- {/each} -
- -
- - {/if} -
-
- - diff --git a/packages/builder/src/pages/builder/portal/settings/general.svelte b/packages/builder/src/pages/builder/portal/settings/general.svelte index 8ee249fae5..cd5709d493 100644 --- a/packages/builder/src/pages/builder/portal/settings/general.svelte +++ b/packages/builder/src/pages/builder/portal/settings/general.svelte @@ -57,78 +57,76 @@ } -
- -
- General - - General is the place where you edit your organisation name, logo. You - can also configure your platform URL as well as turn on or off - analytics. - + + + General + + General is the place where you edit your organisation name, logo. You can + also configure your platform URL as well as turn on or off analytics. + + + + + Information + Here you can update your logo and organization name. + +
+
+ +
- -
- Information - Here you can update your logo and organization name. -
-
- - -
- + - -
- Platform - Here you can set up general platform settings. -
-
- - -
-
+
+ + + Platform + Here you can set up general platform settings. + +
+
+ +
- -
+
+ + + Analytics - + If you would like to send analytics that help us make Budibase better, please let us know below. -
-
- - -
+ +
+
+ +
-
- -
-
+
+ +
+
diff --git a/packages/builder/src/stores/backend/auth.js b/packages/builder/src/stores/backend/auth.js index c86836ae0f..40420657ec 100644 --- a/packages/builder/src/stores/backend/auth.js +++ b/packages/builder/src/stores/backend/auth.js @@ -33,6 +33,25 @@ export function createAuthStore() { await response.json() store.update(state => ({ ...state, user: null })) }, + forgotPassword: async email => { + const response = await api.post(`/api/admin/auth/reset`, { + email, + }) + if (response.status !== 200) { + throw "Unable to send email with reset link" + } + await response.json() + }, + resetPassword: async (password, code) => { + const response = await api.post(`/api/admin/auth/reset/update`, { + password, + resetCode: code, + }) + if (response.status !== 200) { + throw "Unable to reset password" + } + await response.json() + }, createUser: async user => { const response = await api.post(`/api/admin/users`, user) if (response.status !== 200) { diff --git a/packages/server/src/constants/index.js b/packages/server/src/constants/index.js index e4a65a94f6..7d80f67a1c 100644 --- a/packages/server/src/constants/index.js +++ b/packages/server/src/constants/index.js @@ -50,6 +50,24 @@ exports.USERS_TABLE_SCHEMA = { fieldName: "email", name: "email", }, + firstName: { + name: "firstName", + fieldName: "firstName", + type: exports.FieldTypes.STRING, + constraints: { + type: exports.FieldTypes.STRING, + presence: false, + }, + }, + lastName: { + name: "lastName", + fieldName: "lastName", + type: exports.FieldTypes.STRING, + constraints: { + type: exports.FieldTypes.STRING, + presence: false, + }, + }, roleId: { fieldName: "roleId", name: "roleId", diff --git a/packages/worker/src/api/controllers/admin/auth.js b/packages/worker/src/api/controllers/admin/auth.js index 7298d726b3..5304ac85d1 100644 --- a/packages/worker/src/api/controllers/admin/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -54,10 +54,13 @@ exports.reset = async ctx => { } try { const user = await getGlobalUserByEmail(email) - await sendEmail(email, EmailTemplatePurpose.PASSWORD_RECOVERY, { - user, - subject: "{{ company }} platform password reset", - }) + // only if user exists, don't error though if they don't + if (user) { + await sendEmail(email, EmailTemplatePurpose.PASSWORD_RECOVERY, { + user, + subject: "{{ company }} platform password reset", + }) + } } catch (err) { // don't throw any kind of error to the user, this might give away something } diff --git a/packages/worker/src/api/controllers/auth.js b/packages/worker/src/api/controllers/auth.js deleted file mode 100644 index 153f7f8523..0000000000 --- a/packages/worker/src/api/controllers/auth.js +++ /dev/null @@ -1,93 +0,0 @@ -const authPkg = require("@budibase/auth") -const { google } = require("@budibase/auth/src/middleware") -const { Configs } = require("../../constants") -const CouchDB = require("../../db") -const { clearCookie } = authPkg.utils -const { Cookies } = authPkg.constants -const { passport } = authPkg.auth - -const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name - -exports.authenticate = async (ctx, next) => { - return passport.authenticate("local", async (err, user) => { - if (err) { - return ctx.throw(403, "Unauthorized") - } - - const expires = new Date() - expires.setDate(expires.getDate() + 1) - - if (!user) { - return ctx.throw(403, "Unauthorized") - } - - ctx.cookies.set(Cookies.Auth, user.token, { - expires, - path: "/", - httpOnly: false, - overwrite: true, - }) - - delete user.token - - ctx.body = { user } - })(ctx, next) -} - -exports.logout = async ctx => { - clearCookie(ctx, Cookies.Auth) - ctx.body = { message: "User logged out" } -} - -/** - * The initial call that google authentication makes to take you to the google login screen. - * On a successful login, you will be redirected to the googleAuth callback route. - */ -exports.googlePreAuth = async (ctx, next) => { - const db = new CouchDB(GLOBAL_DB) - const config = await authPkg.db.getScopedFullConfig(db, { - type: Configs.GOOGLE, - group: ctx.query.group, - }) - const strategy = await google.strategyFactory(config) - - return passport.authenticate(strategy, { - scope: ["profile", "email"], - })(ctx, next) -} - -exports.googleAuth = async (ctx, next) => { - const db = new CouchDB(GLOBAL_DB) - - const config = await authPkg.db.getScopedFullConfig(db, { - type: Configs.GOOGLE, - group: ctx.query.group, - }) - const strategy = await google.strategyFactory(config) - - return passport.authenticate( - strategy, - { successRedirect: "/", failureRedirect: "/error" }, - async (err, user) => { - if (err) { - return ctx.throw(403, "Unauthorized") - } - - const expires = new Date() - expires.setDate(expires.getDate() + 1) - - if (!user) { - return ctx.throw(403, "Unauthorized") - } - - ctx.cookies.set(Cookies.Auth, user.token, { - expires, - path: "/", - httpOnly: false, - overwrite: true, - }) - - ctx.redirect("/") - } - )(ctx, next) -} diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index 8d383b385c..179f662a96 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -117,6 +117,10 @@ async function getSmtpConfiguration(db, groupId = null) { * @return {Promise} returns true if there is a configuration that can be used. */ exports.isEmailConfigured = async (groupId = null) => { + // when "testing" simply return true + if (TEST_MODE) { + return true + } const db = new CouchDB(GLOBAL_DB) const config = await getSmtpConfiguration(db, groupId) return config != null diff --git a/packages/worker/src/utilities/templates.js b/packages/worker/src/utilities/templates.js index 5e712eea1c..86436a2f29 100644 --- a/packages/worker/src/utilities/templates.js +++ b/packages/worker/src/utilities/templates.js @@ -35,7 +35,7 @@ exports.getSettingsTemplateContext = async (purpose, code = null) => { case EmailTemplatePurpose.PASSWORD_RECOVERY: context[InternalTemplateBindings.RESET_CODE] = code context[InternalTemplateBindings.RESET_URL] = checkSlashesInUrl( - `${URL}/reset?code=${code}` + `${URL}/builder/auth/reset?code=${code}` ) break case EmailTemplatePurpose.INVITATION: