Renaming groups to workspaces.

This commit is contained in:
mike12345567 2021-07-13 17:27:04 +01:00
parent e692223661
commit 004f719dde
14 changed files with 70 additions and 74 deletions

View File

@ -12,7 +12,7 @@ exports.GlobalRoles = {
OWNER: "owner", OWNER: "owner",
ADMIN: "admin", ADMIN: "admin",
BUILDER: "builder", BUILDER: "builder",
GROUP_MANAGER: "group_manager", WORKSPACE_MANAGER: "workspace_manager",
} }
exports.Configs = { exports.Configs = {

View File

@ -19,7 +19,7 @@ exports.StaticDatabases = {
const DocumentTypes = { const DocumentTypes = {
USER: "us", USER: "us",
GROUP: "group", WORKSPACE: "workspace",
CONFIG: "config", CONFIG: "config",
TEMPLATE: "template", TEMPLATE: "template",
APP: "app", APP: "app",
@ -61,21 +61,21 @@ function getDocParams(docType, docId = null, otherProps = {}) {
} }
/** /**
* Generates a new group ID. * Generates a new workspace ID.
* @returns {string} The new group ID which the group doc can be stored under. * @returns {string} The new workspace ID which the workspace doc can be stored under.
*/ */
exports.generateGroupID = () => { exports.generateWorkspaceID = () => {
return `${DocumentTypes.GROUP}${SEPARATOR}${newid()}` return `${DocumentTypes.WORKSPACE}${SEPARATOR}${newid()}`
} }
/** /**
* Gets parameters for retrieving groups. * Gets parameters for retrieving workspaces.
*/ */
exports.getGroupParams = (id = "", otherProps = {}) => { exports.getWorkspaceParams = (id = "", otherProps = {}) => {
return { return {
...otherProps, ...otherProps,
startkey: `${DocumentTypes.GROUP}${SEPARATOR}${id}`, startkey: `${DocumentTypes.WORKSPACE}${SEPARATOR}${id}`,
endkey: `${DocumentTypes.GROUP}${SEPARATOR}${id}${UNICODE_MAX}`, endkey: `${DocumentTypes.WORKSPACE}${SEPARATOR}${id}${UNICODE_MAX}`,
} }
} }
@ -103,14 +103,14 @@ exports.getGlobalUserParams = (globalId, otherProps = {}) => {
/** /**
* Generates a template ID. * Generates a template ID.
* @param ownerId The owner/user of the template, this could be global or a group level. * @param ownerId The owner/user of the template, this could be global or a workspace level.
*/ */
exports.generateTemplateID = ownerId => { exports.generateTemplateID = ownerId => {
return `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}` return `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}${newid()}`
} }
/** /**
* Gets parameters for retrieving templates. Owner ID must be specified, either global or a group level. * Gets parameters for retrieving templates. Owner ID must be specified, either global or a workspace level.
*/ */
exports.getTemplateParams = (ownerId, templateId, otherProps = {}) => { exports.getTemplateParams = (ownerId, templateId, otherProps = {}) => {
if (!templateId) { if (!templateId) {
@ -214,8 +214,8 @@ exports.dbExists = async (CouchDB, dbName) => {
* Generates a new configuration ID. * Generates a new configuration ID.
* @returns {string} The new configuration ID which the config doc can be stored under. * @returns {string} The new configuration ID which the config doc can be stored under.
*/ */
const generateConfigID = ({ type, group, user }) => { const generateConfigID = ({ type, workspace, user }) => {
const scope = [type, group, user].filter(Boolean).join(SEPARATOR) const scope = [type, workspace, user].filter(Boolean).join(SEPARATOR)
return `${DocumentTypes.CONFIG}${SEPARATOR}${scope}` return `${DocumentTypes.CONFIG}${SEPARATOR}${scope}`
} }
@ -223,8 +223,8 @@ const generateConfigID = ({ type, group, user }) => {
/** /**
* Gets parameters for retrieving configurations. * Gets parameters for retrieving configurations.
*/ */
const getConfigParams = ({ type, group, user }, otherProps = {}) => { const getConfigParams = ({ type, workspace, user }, otherProps = {}) => {
const scope = [type, group, user].filter(Boolean).join(SEPARATOR) const scope = [type, workspace, user].filter(Boolean).join(SEPARATOR)
return { return {
...otherProps, ...otherProps,
@ -234,15 +234,15 @@ const getConfigParams = ({ type, group, user }, otherProps = {}) => {
} }
/** /**
* Returns the most granular configuration document from the DB based on the type, group and userID passed. * Returns the most granular configuration document from the DB based on the type, workspace and userID passed.
* @param {Object} db - db instance to query * @param {Object} db - db instance to query
* @param {Object} scopes - the type, group and userID scopes of the configuration. * @param {Object} scopes - the type, workspace and userID scopes of the configuration.
* @returns The most granular configuration document based on the scope. * @returns The most granular configuration document based on the scope.
*/ */
const getScopedFullConfig = async function (db, { type, user, group }) { const getScopedFullConfig = async function (db, { type, user, workspace }) {
const response = await db.allDocs( const response = await db.allDocs(
getConfigParams( getConfigParams(
{ type, user, group }, { type, user, workspace },
{ {
include_docs: true, include_docs: true,
} }
@ -252,14 +252,14 @@ const getScopedFullConfig = async function (db, { type, user, group }) {
function determineScore(row) { function determineScore(row) {
const config = row.doc const config = row.doc
// Config is specific to a user and a group // Config is specific to a user and a workspace
if (config._id.includes(generateConfigID({ type, user, group }))) { if (config._id.includes(generateConfigID({ type, user, workspace }))) {
return 4 return 4
} else if (config._id.includes(generateConfigID({ type, user }))) { } else if (config._id.includes(generateConfigID({ type, user }))) {
// Config is specific to a user only // Config is specific to a user only
return 3 return 3
} else if (config._id.includes(generateConfigID({ type, group }))) { } else if (config._id.includes(generateConfigID({ type, workspace }))) {
// Config is specific to a group only // Config is specific to a workspace only
return 2 return 2
} else if (config._id.includes(generateConfigID({ type }))) { } else if (config._id.includes(generateConfigID({ type }))) {
// Config is specific to a type only // Config is specific to a type only

View File

@ -19,7 +19,7 @@ module.exports.definition = {
properties: { properties: {
text: { text: {
type: "string", type: "string",
title: "URL", title: "Log",
}, },
}, },
required: ["text"], required: ["text"],

View File

@ -102,7 +102,7 @@ exports.googlePreAuth = async (ctx, next) => {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const config = await authPkg.db.getScopedConfig(db, { const config = await authPkg.db.getScopedConfig(db, {
type: Configs.GOOGLE, type: Configs.GOOGLE,
group: ctx.query.group, workspace: ctx.query.workspace,
}) })
const strategy = await google.strategyFactory(config) const strategy = await google.strategyFactory(config)
@ -116,7 +116,7 @@ exports.googleAuth = async (ctx, next) => {
const config = await authPkg.db.getScopedConfig(db, { const config = await authPkg.db.getScopedConfig(db, {
type: Configs.GOOGLE, type: Configs.GOOGLE,
group: ctx.query.group, workspace: ctx.query.workspace,
}) })
const strategy = await google.strategyFactory(config) const strategy = await google.strategyFactory(config)

View File

@ -16,13 +16,13 @@ const GLOBAL_DB = StaticDatabases.GLOBAL.name
exports.save = async function (ctx) { exports.save = async function (ctx) {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const { type, group, user, config } = ctx.request.body const { type, workspace, user, config } = ctx.request.body
// Config does not exist yet // Config does not exist yet
if (!ctx.request.body._id) { if (!ctx.request.body._id) {
ctx.request.body._id = generateConfigID({ ctx.request.body._id = generateConfigID({
type, type,
group, workspace,
user, user,
}) })
} }
@ -65,17 +65,17 @@ exports.fetch = async function (ctx) {
/** /**
* Gets the most granular config for a particular configuration type. * Gets the most granular config for a particular configuration type.
* The hierarchy is type -> group -> user. * The hierarchy is type -> workspace -> user.
*/ */
exports.find = async function (ctx) { exports.find = async function (ctx) {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const { userId, groupId } = ctx.query const { userId, workspaceId } = ctx.query
if (groupId && userId) { if (workspaceId && userId) {
const group = await db.get(groupId) const workspace = await db.get(workspaceId)
const userInGroup = group.users.some(groupUser => groupUser === userId) const userInWorkspace = workspace.users.some(workspaceUser => workspaceUser === userId)
if (!ctx.user.admin && !userInGroup) { if (!ctx.user.admin && !userInWorkspace) {
ctx.throw(400, `User is not in specified group: ${group}.`) ctx.throw(400, `User is not in specified workspace: ${workspace}.`)
} }
} }
@ -84,7 +84,7 @@ exports.find = async function (ctx) {
const scopedConfig = await getScopedFullConfig(db, { const scopedConfig = await getScopedFullConfig(db, {
type: ctx.params.type, type: ctx.params.type,
user: userId, user: userId,
group: groupId, workspace: workspaceId,
}) })
if (scopedConfig) { if (scopedConfig) {

View File

@ -5,7 +5,7 @@ const authPkg = require("@budibase/auth")
const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name
exports.sendEmail = async ctx => { exports.sendEmail = async ctx => {
const { groupId, email, userId, purpose, contents, from, subject } = const { workspaceId, email, userId, purpose, contents, from, subject } =
ctx.request.body ctx.request.body
let user let user
if (userId) { if (userId) {
@ -13,7 +13,7 @@ exports.sendEmail = async ctx => {
user = await db.get(userId) user = await db.get(userId)
} }
const response = await sendEmail(email, purpose, { const response = await sendEmail(email, purpose, {
groupId, workspaceId,
user, user,
contents, contents,
from, from,

View File

@ -1,20 +1,20 @@
const CouchDB = require("../../../db") const CouchDB = require("../../../db")
const { getGroupParams, generateGroupID, StaticDatabases } = const { getWorkspaceParams, generateWorkspaceID, StaticDatabases } =
require("@budibase/auth").db require("@budibase/auth").db
const GLOBAL_DB = StaticDatabases.GLOBAL.name const GLOBAL_DB = StaticDatabases.GLOBAL.name
exports.save = async function (ctx) { exports.save = async function (ctx) {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const groupDoc = ctx.request.body const workspaceDoc = ctx.request.body
// Group does not exist yet // workspace does not exist yet
if (!groupDoc._id) { if (!workspaceDoc._id) {
groupDoc._id = generateGroupID() workspaceDoc._id = generateWorkspaceID()
} }
try { try {
const response = await db.post(groupDoc) const response = await db.post(workspaceDoc)
ctx.body = { ctx.body = {
_id: response.id, _id: response.id,
_rev: response.rev, _rev: response.rev,
@ -27,7 +27,7 @@ exports.save = async function (ctx) {
exports.fetch = async function (ctx) { exports.fetch = async function (ctx) {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const response = await db.allDocs( const response = await db.allDocs(
getGroupParams(undefined, { getWorkspaceParams(undefined, {
include_docs: true, include_docs: true,
}) })
) )
@ -49,7 +49,7 @@ exports.destroy = async function (ctx) {
try { try {
await db.remove(id, rev) await db.remove(id, rev)
ctx.body = { message: "Group deleted successfully" } ctx.body = { message: "Workspace deleted successfully" }
} catch (err) { } catch (err) {
ctx.throw(err.status, err) ctx.throw(err.status, err)
} }

View File

@ -46,7 +46,7 @@ function buildConfigSaveValidation() {
return joiValidator.body(Joi.object({ return joiValidator.body(Joi.object({
_id: Joi.string().optional(), _id: Joi.string().optional(),
_rev: Joi.string().optional(), _rev: Joi.string().optional(),
group: Joi.string().optional(), workspace: Joi.string().optional(),
type: Joi.string().valid(...Object.values(Configs)).required(), type: Joi.string().valid(...Object.values(Configs)).required(),
config: Joi.alternatives() config: Joi.alternatives()
.conditional("type", { .conditional("type", {

View File

@ -12,8 +12,8 @@ function buildEmailSendValidation() {
return joiValidator.body(Joi.object({ return joiValidator.body(Joi.object({
email: Joi.string().email(), email: Joi.string().email(),
purpose: Joi.string().valid(...Object.values(EmailTemplatePurpose)), purpose: Joi.string().valid(...Object.values(EmailTemplatePurpose)),
groupId: Joi.string().allow("", null), workspaceId: Joi.string().allow("", null),
fromt: Joi.string().allow("", null), from: Joi.string().allow("", null),
contents: Joi.string().allow("", null), contents: Joi.string().allow("", null),
subject: Joi.string().allow("", null), subject: Joi.string().allow("", null),
}).required().unknown(true)) }).required().unknown(true))

View File

@ -1,12 +1,12 @@
const Router = require("@koa/router") const Router = require("@koa/router")
const controller = require("../../controllers/admin/groups") const controller = require("../../controllers/admin/workspaces")
const joiValidator = require("../../../middleware/joi-validator") const joiValidator = require("../../../middleware/joi-validator")
const adminOnly = require("../../../middleware/adminOnly") const adminOnly = require("../../../middleware/adminOnly")
const Joi = require("joi") const Joi = require("joi")
const router = Router() const router = Router()
function buildGroupSaveValidation() { function buildWorkspaceSaveValidation() {
// prettier-ignore // prettier-ignore
return joiValidator.body(Joi.object({ return joiValidator.body(Joi.object({
_id: Joi.string().optional(), _id: Joi.string().optional(),
@ -26,13 +26,13 @@ function buildGroupSaveValidation() {
router router
.post( .post(
"/api/admin/groups", "/api/admin/workspaces",
adminOnly, adminOnly,
buildGroupSaveValidation(), buildWorkspaceSaveValidation(),
controller.save controller.save
) )
.get("/api/admin/groups", controller.fetch) .delete("/api/admin/workspaces/:id", adminOnly, controller.destroy)
.delete("/api/admin/groups/:id", adminOnly, controller.destroy) .get("/api/admin/workspaces", controller.fetch)
.get("/api/admin/groups/:id", controller.find) .get("/api/admin/workspaces/:id", controller.find)
module.exports = router module.exports = router

View File

@ -1,6 +1,6 @@
const userRoutes = require("./admin/users") const userRoutes = require("./admin/users")
const configRoutes = require("./admin/configs") const configRoutes = require("./admin/configs")
const groupRoutes = require("./admin/groups") const workspaceRoutes = require("./admin/workspaces")
const templateRoutes = require("./admin/templates") const templateRoutes = require("./admin/templates")
const emailRoutes = require("./admin/email") const emailRoutes = require("./admin/email")
const authRoutes = require("./admin/auth") const authRoutes = require("./admin/auth")
@ -11,7 +11,7 @@ const appRoutes = require("./app")
exports.routes = [ exports.routes = [
configRoutes, configRoutes,
userRoutes, userRoutes,
groupRoutes, workspaceRoutes,
authRoutes, authRoutes,
appRoutes, appRoutes,
templateRoutes, templateRoutes,

View File

@ -1,6 +1,6 @@
module.exports = { module.exports = {
email: require("../../../controllers/admin/email"), email: require("../../../controllers/admin/email"),
groups: require("../../../controllers/admin/groups"), workspaces: require("../../../controllers/admin/workspaces"),
config: require("../../../controllers/admin/configs"), config: require("../../../controllers/admin/configs"),
templates: require("../../../controllers/admin/templates"), templates: require("../../../controllers/admin/templates"),
users: require("../../../controllers/admin/users"), users: require("../../../controllers/admin/users"),

View File

@ -8,10 +8,6 @@ exports.UserStatus = {
INACTIVE: "inactive", INACTIVE: "inactive",
} }
exports.Groups = {
ALL_USERS: "all_users",
}
exports.Configs = Configs exports.Configs = Configs
exports.ConfigUploads = { exports.ConfigUploads = {

View File

@ -101,31 +101,31 @@ async function buildEmail(purpose, email, context, { user, contents } = {}) {
/** /**
* Utility function for finding most valid SMTP configuration. * Utility function for finding most valid SMTP configuration.
* @param {object} db The CouchDB database which is to be looked up within. * @param {object} db The CouchDB database which is to be looked up within.
* @param {string|null} groupId If using finer grain control of configs a group can be used. * @param {string|null} workspaceId If using finer grain control of configs a workspace can be used.
* @return {Promise<object|null>} returns the SMTP configuration if it exists * @return {Promise<object|null>} returns the SMTP configuration if it exists
*/ */
async function getSmtpConfiguration(db, groupId = null) { async function getSmtpConfiguration(db, workspaceId = null) {
const params = { const params = {
type: Configs.SMTP, type: Configs.SMTP,
} }
if (groupId) { if (workspaceId) {
params.group = groupId params.workspace = workspaceId
} }
return getScopedConfig(db, params) return getScopedConfig(db, params)
} }
/** /**
* Checks if a SMTP config exists based on passed in parameters. * Checks if a SMTP config exists based on passed in parameters.
* @param groupId * @param workspaceId
* @return {Promise<boolean>} returns true if there is a configuration that can be used. * @return {Promise<boolean>} returns true if there is a configuration that can be used.
*/ */
exports.isEmailConfigured = async (groupId = null) => { exports.isEmailConfigured = async (workspaceId = null) => {
// when "testing" simply return true // when "testing" simply return true
if (TEST_MODE) { if (TEST_MODE) {
return true return true
} }
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const config = await getSmtpConfiguration(db, groupId) const config = await getSmtpConfiguration(db, workspaceId)
return config != null return config != null
} }
@ -134,7 +134,7 @@ exports.isEmailConfigured = async (groupId = null) => {
* send an email using it. * send an email using it.
* @param {string} email The email address to send to. * @param {string} email The email address to send to.
* @param {string} purpose The purpose of the email being sent (e.g. reset password). * @param {string} purpose The purpose of the email being sent (e.g. reset password).
* @param {string|undefined} groupId If finer grain controls being used then this will lookup config for group. * @param {string|undefined} workspaceId If finer grain controls being used then this will lookup config for workspace.
* @param {object|undefined} user If sending to an existing user the object can be provided, this is used in the context. * @param {object|undefined} user If sending to an existing user the object can be provided, this is used in the context.
* @param {string|undefined} from If sending from an address that is not what is configured in the SMTP config. * @param {string|undefined} from If sending from an address that is not what is configured in the SMTP config.
* @param {string|undefined} contents If sending a custom email then can supply contents which will be added to it. * @param {string|undefined} contents If sending a custom email then can supply contents which will be added to it.
@ -146,10 +146,10 @@ exports.isEmailConfigured = async (groupId = null) => {
exports.sendEmail = async ( exports.sendEmail = async (
email, email,
purpose, purpose,
{ groupId, user, from, contents, subject, info } = {} { workspaceId, user, from, contents, subject, info } = {}
) => { ) => {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
let config = (await getSmtpConfiguration(db, groupId)) || {} let config = (await getSmtpConfiguration(db, workspaceId)) || {}
if (Object.keys(config).length === 0 && !TEST_MODE) { if (Object.keys(config).length === 0 && !TEST_MODE) {
throw "Unable to find SMTP configuration." throw "Unable to find SMTP configuration."
} }