diff --git a/packages/builder/cypress/integration/createUser.spec.js b/packages/builder/cypress/integration/createUser.spec.js
index cbde6179b2..a5f9934dd7 100644
--- a/packages/builder/cypress/integration/createUser.spec.js
+++ b/packages/builder/cypress/integration/createUser.spec.js
@@ -9,7 +9,7 @@ context('Create a User', () => {
// https://on.cypress.io/interacting-with-elements
it('should create a user', () => {
- cy.createUser("bbuser", "test", "ADMIN")
+ cy.createUser("bbuser@test.com", "test", "ADMIN")
// // Check to make sure user was created!
cy.contains("bbuser").should('be.visible')
diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js
index ecb4eac6ce..94faa124a8 100644
--- a/packages/builder/cypress/support/commands.js
+++ b/packages/builder/cypress/support/commands.js
@@ -44,9 +44,9 @@ Cypress.Commands.add("createApp", name => {
cy.contains("Next").click()
- cy.get("input[name=username]")
+ cy.get("input[name=email]")
.click()
- .type("test")
+ .type("test@test.com")
cy.get("input[name=password]")
.click()
.type("test")
@@ -111,7 +111,7 @@ Cypress.Commands.add("addRow", values => {
})
})
-Cypress.Commands.add("createUser", (username, password, role) => {
+Cypress.Commands.add("createUser", (email, password, role) => {
// Create User
cy.contains("Users").click()
@@ -123,7 +123,7 @@ Cypress.Commands.add("createUser", (username, password, role) => {
.type(password)
cy.get("input")
.eq(1)
- .type(username)
+ .type(email)
cy.get("select")
.first()
.select(role)
diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
index 8bb4dc36dd..7e26b2155e 100644
--- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
@@ -62,6 +62,8 @@
{:else if value.customType === 'password'}
+ {:else if value.customType === 'email'}
+
{:else if value.customType === 'table'}
{:else if value.customType === 'row'}
diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte
index 1a93ee3bb6..b88397b6c4 100644
--- a/packages/builder/src/components/start/CreateAppModal.svelte
+++ b/packages/builder/src/components/start/CreateAppModal.svelte
@@ -52,7 +52,9 @@
applicationName: string().required("Your application must have a name."),
},
{
- username: string().required("Your application needs a first user."),
+ email: string()
+ .email()
+ .required("Your application needs a first user."),
password: string().required(
"Please enter a password for your first user."
),
@@ -159,8 +161,7 @@
// Create user
const user = {
- name: $createAppStore.values.username,
- username: $createAppStore.values.username,
+ email: $createAppStore.values.email,
password: $createAppStore.values.password,
roleId: $createAppStore.values.roleId,
}
diff --git a/packages/builder/src/components/start/Steps/User.svelte b/packages/builder/src/components/start/Steps/User.svelte
index 0bf9ce19cb..397a06be94 100644
--- a/packages/builder/src/components/start/Steps/User.svelte
+++ b/packages/builder/src/components/start/Steps/User.svelte
@@ -2,18 +2,18 @@
import { Input, Select } from "@budibase/bbui"
export let validationErrors
- let blurred = { username: false, password: false }
+ let blurred = { email: false, password: false }
(blurred.username = true)}
- label="Username"
- name="username"
- placeholder="Username"
- type="name"
- error={blurred.username && validationErrors.username} />
+ on:input={() => (blurred.email = true)}
+ label="Email"
+ name="email"
+ placeholder="Email"
+ type="email"
+ error={blurred.email && validationErrors.email} />
(blurred.password = true)}
label="Password"
diff --git a/packages/builder/src/constants/index.js b/packages/builder/src/constants/index.js
index c78dddc8c9..f2184290ae 100644
--- a/packages/builder/src/constants/index.js
+++ b/packages/builder/src/constants/index.js
@@ -10,7 +10,7 @@ export const FrontendTypes = {
}
// fields on the user table that cannot be edited
-export const UNEDITABLE_USER_FIELDS = ["username", "password", "roleId"]
+export const UNEDITABLE_USER_FIELDS = ["email", "password", "roleId"]
export const LAYOUT_NAMES = {
MASTER: {
diff --git a/packages/client/src/api/auth.js b/packages/client/src/api/auth.js
index 9273a00cc7..ddaaa7a491 100644
--- a/packages/client/src/api/auth.js
+++ b/packages/client/src/api/auth.js
@@ -3,15 +3,15 @@ import API from "./api"
/**
* Performs a log in request.
*/
-export const logIn = async ({ username, password }) => {
- if (!username) {
- return API.error("Please enter your username")
+export const logIn = async ({ email, password }) => {
+ if (!email) {
+ return API.error("Please enter your email")
}
if (!password) {
return API.error("Please enter your password")
}
return await API.post({
url: "/api/authenticate",
- body: { username, password },
+ body: { email, password },
})
}
diff --git a/packages/client/src/store/auth.js b/packages/client/src/store/auth.js
index a7c91a0972..d641113b4a 100644
--- a/packages/client/src/store/auth.js
+++ b/packages/client/src/store/auth.js
@@ -5,8 +5,8 @@ import { writable } from "svelte/store"
const createAuthStore = () => {
const store = writable("")
- const logIn = async ({ username, password }) => {
- const user = await API.logIn({ username, password })
+ const logIn = async ({ email, password }) => {
+ const user = await API.logIn({ email, password })
if (!user.error) {
store.set(user.token)
location.reload()
diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js
index de872ebfc4..bb4e725876 100644
--- a/packages/server/src/api/controllers/auth.js
+++ b/packages/server/src/api/controllers/auth.js
@@ -10,21 +10,21 @@ exports.authenticate = async ctx => {
const appId = ctx.appId
if (!appId) ctx.throw(400, "No appId")
- const { username, password } = ctx.request.body
+ const { email, password } = ctx.request.body
- if (!username) ctx.throw(400, "Username Required.")
+ if (!email) ctx.throw(400, "Email Required.")
if (!password) ctx.throw(400, "Password Required.")
- // Check the user exists in the instance DB by username
+ // Check the user exists in the instance DB by email
const db = new CouchDB(appId)
const app = await db.get(appId)
let dbUser
try {
- dbUser = await db.get(generateUserID(username))
+ dbUser = await db.get(generateUserID(email))
} catch (_) {
// do not want to throw a 404 - as this could be
- // used to determine valid usernames
+ // used to determine valid emails
ctx.throw(401, "Invalid Credentials")
}
diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js
index f20ccd3d7e..72f71dcb2b 100644
--- a/packages/server/src/api/controllers/user.js
+++ b/packages/server/src/api/controllers/user.js
@@ -18,10 +18,10 @@ exports.fetch = async function(ctx) {
exports.create = async function(ctx) {
const db = new CouchDB(ctx.user.appId)
- const { username, password, name, roleId, permissions } = ctx.request.body
+ const { email, password, roleId, permissions } = ctx.request.body
- if (!username || !password) {
- ctx.throw(400, "Username and Password Required.")
+ if (!email || !password) {
+ ctx.throw(400, "email and Password Required.")
}
const role = await checkRole(db, roleId)
@@ -29,10 +29,9 @@ exports.create = async function(ctx) {
if (!role) ctx.throw(400, "Invalid Role")
const user = {
- _id: generateUserID(username),
- username,
+ _id: generateUserID(email),
+ email,
password: await bcrypt.hash(password),
- name: name || username,
type: "user",
roleId,
permissions: permissions || [BUILTIN_PERMISSION_NAMES.POWER],
@@ -46,8 +45,7 @@ exports.create = async function(ctx) {
ctx.userId = response._id
ctx.body = {
_rev: response.rev,
- username,
- name,
+ email,
}
} catch (err) {
if (err.status === 409) {
@@ -68,22 +66,22 @@ exports.update = async function(ctx) {
user._rev = response.rev
ctx.status = 200
- ctx.message = `User ${ctx.request.body.username} updated successfully.`
+ ctx.message = `User ${ctx.request.body.email} updated successfully.`
ctx.body = response
}
exports.destroy = async function(ctx) {
const database = new CouchDB(ctx.user.appId)
- await database.destroy(generateUserID(ctx.params.username))
- ctx.message = `User ${ctx.params.username} deleted.`
+ await database.destroy(generateUserID(ctx.params.email))
+ ctx.message = `User ${ctx.params.email} deleted.`
ctx.status = 200
}
exports.find = async function(ctx) {
const database = new CouchDB(ctx.user.appId)
- const user = await database.get(generateUserID(ctx.params.username))
+ const user = await database.get(generateUserID(ctx.params.email))
ctx.body = {
- username: user.username,
+ email: user.email,
name: user.name,
_rev: user._rev,
}
diff --git a/packages/server/src/api/routes/tests/couchTestUtils.js b/packages/server/src/api/routes/tests/couchTestUtils.js
index c7846f85b8..c48627b8f9 100644
--- a/packages/server/src/api/routes/tests/couchTestUtils.js
+++ b/packages/server/src/api/routes/tests/couchTestUtils.js
@@ -116,7 +116,7 @@ exports.clearApplications = async request => {
exports.createUser = async (
request,
appId,
- username = "babs",
+ email = "babs@babs.com",
password = "babs_password"
) => {
const res = await request
@@ -124,7 +124,7 @@ exports.createUser = async (
.set(exports.defaultHeaders(appId))
.send({
name: "Bill",
- username,
+ email,
password,
roleId: BUILTIN_ROLE_IDS.POWER,
})
@@ -172,15 +172,14 @@ const createUserWithPermissions = async (
request,
appId,
permissions,
- username
+ email
) => {
- const password = `password_${username}`
+ const password = `password_${email}`
await request
.post(`/api/users`)
.set(exports.defaultHeaders(appId))
.send({
- name: username,
- username,
+ email,
password,
roleId: BUILTIN_ROLE_IDS.POWER,
permissions,
@@ -201,7 +200,7 @@ const createUserWithPermissions = async (
Cookie: `budibase:${appId}:local=${anonToken}`,
"x-budibase-app-id": appId,
})
- .send({ username, password })
+ .send({ email, password })
// returning necessary request headers
return {
diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js
index 96e5923d1d..8034f06773 100644
--- a/packages/server/src/api/routes/tests/user.spec.js
+++ b/packages/server/src/api/routes/tests/user.spec.js
@@ -34,8 +34,8 @@ describe("/users", () => {
describe("fetch", () => {
it("returns a list of users from an instance db", async () => {
- await createUser(request, appId, "brenda", "brendas_password")
- await createUser(request, appId, "pam", "pam_password")
+ await createUser(request, appId, "brenda@brenda.com", "brendas_password")
+ await createUser(request, appId, "pam@pam.com", "pam_password")
const res = await request
.get(`/api/users`)
.set(defaultHeaders(appId))
@@ -43,12 +43,12 @@ describe("/users", () => {
.expect(200)
expect(res.body.length).toBe(2)
- expect(res.body.find(u => u.username === "brenda")).toBeDefined()
- expect(res.body.find(u => u.username === "pam")).toBeDefined()
+ expect(res.body.find(u => u.email === "brenda@brenda.com")).toBeDefined()
+ expect(res.body.find(u => u.email === "pam@pam.com")).toBeDefined()
})
it("should apply authorization to endpoint", async () => {
- await createUser(request, appId, "brenda", "brendas_password")
+ await createUser(request, appId, "brenda@brenda.com", "brendas_password")
await testPermissionsForEndpoint({
request,
method: "GET",
@@ -62,12 +62,11 @@ describe("/users", () => {
})
describe("create", () => {
-
it("returns a success message when a user is successfully created", async () => {
const res = await request
.post(`/api/users`)
.set(defaultHeaders(appId))
- .send({ name: "Bill", username: "bill", password: "bills_password", roleId: BUILTIN_ROLE_IDS.POWER })
+ .send({ email: "bill@bill.com", password: "bills_password", roleId: BUILTIN_LEVEL_IDS.POWER })
.expect(200)
.expect('Content-Type', /json/)
@@ -79,7 +78,7 @@ describe("/users", () => {
await testPermissionsForEndpoint({
request,
method: "POST",
- body: { name: "brandNewUser", username: "brandNewUser", password: "yeeooo", roleId: BUILTIN_ROLE_IDS.POWER },
+ body: { email: "brandNewUser@user.com", password: "yeeooo", roleId: BUILTIN_LEVEL_IDS.POWER },
url: `/api/users`,
appId: appId,
permName1: BUILTIN_PERMISSION_NAMES.ADMIN,
diff --git a/packages/server/src/api/routes/user.js b/packages/server/src/api/routes/user.js
index 9394d842bd..1ad1d2363e 100644
--- a/packages/server/src/api/routes/user.js
+++ b/packages/server/src/api/routes/user.js
@@ -16,7 +16,7 @@ router
controller.fetch
)
.get(
- "/api/users/:username",
+ "/api/users/:email",
authorized(PermissionTypes.USER, PermissionLevels.READ),
controller.find
)
@@ -32,7 +32,7 @@ router
controller.create
)
.delete(
- "/api/users/:username",
+ "/api/users/:email",
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
usage,
controller.destroy
diff --git a/packages/server/src/automations/steps/createUser.js b/packages/server/src/automations/steps/createUser.js
index 2e124b148b..a9dce4b66f 100644
--- a/packages/server/src/automations/steps/createUser.js
+++ b/packages/server/src/automations/steps/createUser.js
@@ -5,7 +5,7 @@ const usage = require("../../utilities/usageQuota")
module.exports.definition = {
description: "Create a new user",
- tagline: "Create user {{inputs.username}}",
+ tagline: "Create user {{inputs.email}}",
icon: "ri-user-add-line",
name: "Create User",
type: "ACTION",
@@ -16,9 +16,10 @@ module.exports.definition = {
schema: {
inputs: {
properties: {
- username: {
+ email: {
type: "string",
- title: "Username",
+ customType: "email",
+ title: "Email",
},
password: {
type: "string",
@@ -32,7 +33,7 @@ module.exports.definition = {
pretty: roles.BUILTIN_ROLE_NAME_ARRAY,
},
},
- required: ["username", "password", "roleId"],
+ required: ["email", "password", "roleId"],
},
outputs: {
properties: {
@@ -59,13 +60,13 @@ module.exports.definition = {
}
module.exports.run = async function({ inputs, appId, apiKey }) {
- const { username, password, roleId } = inputs
+ const { email, password, roleId } = inputs
const ctx = {
user: {
appId: appId,
},
request: {
- body: { username, password, roleId },
+ body: { email, password, roleId },
},
}
diff --git a/packages/server/src/constants/index.js b/packages/server/src/constants/index.js
index d691bcee55..587e751600 100644
--- a/packages/server/src/constants/index.js
+++ b/packages/server/src/constants/index.js
@@ -12,17 +12,18 @@ const USERS_TABLE_SCHEMA = {
views: {},
name: "Users",
schema: {
- username: {
+ email: {
type: "string",
constraints: {
type: "string",
+ email: true,
length: {
maximum: "",
},
presence: true,
},
- fieldName: "username",
- name: "username",
+ fieldName: "email",
+ name: "email",
},
roleId: {
fieldName: "roleId",
@@ -35,7 +36,7 @@ const USERS_TABLE_SCHEMA = {
},
},
},
- primaryDisplay: "username",
+ primaryDisplay: "email",
}
exports.AuthTypes = AuthTypes
diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js
index c44e080caa..ea4ab27b0c 100644
--- a/packages/server/src/db/utils.js
+++ b/packages/server/src/db/utils.js
@@ -101,21 +101,21 @@ exports.generateRowID = tableId => {
/**
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
*/
-exports.getUserParams = (username = "", otherProps = {}) => {
+exports.getUserParams = (email = "", otherProps = {}) => {
return getDocParams(
DocumentTypes.ROW,
- `${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${username}`,
+ `${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${email}`,
otherProps
)
}
/**
* Generates a new user ID based on the passed in username.
- * @param {string} username The username which the ID is going to be built up of.
+ * @param {string} email The email which the ID is going to be built up of.
* @returns {string} The new user ID which the user doc can be stored under.
*/
-exports.generateUserID = username => {
- return `${DocumentTypes.ROW}${SEPARATOR}${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${username}`
+exports.generateUserID = email => {
+ return `${DocumentTypes.ROW}${SEPARATOR}${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${email}`
}
/**
diff --git a/packages/standard-components/components.json b/packages/standard-components/components.json
index 7504c15b40..c55c04f119 100644
--- a/packages/standard-components/components.json
+++ b/packages/standard-components/components.json
@@ -56,7 +56,7 @@
},
"login": {
"name": "Login Control",
- "description": "A control that accepts username, password an also handles password resets",
+ "description": "A control that accepts email, password an also handles password resets",
"props": {
"logo": "string",
"title": "string",
diff --git a/packages/standard-components/src/Login.svelte b/packages/standard-components/src/Login.svelte
index 4193f0a684..8a4af82320 100644
--- a/packages/standard-components/src/Login.svelte
+++ b/packages/standard-components/src/Login.svelte
@@ -10,7 +10,7 @@
export let buttonClass = ""
export let inputClass = ""
- let username = ""
+ let email = ""
let password = ""
let loading = false
let error = false
@@ -24,7 +24,7 @@
const login = async () => {
loading = true
- await authStore.actions.logIn({ username, password })
+ await authStore.actions.logIn({ email, password })
loading = false
}
@@ -42,9 +42,9 @@
{#if error}
-
Incorrect username or password
+
Incorrect email or password
{/if}