budibase/packages/worker/dist/api/controllers/global/users.js

262 lines
10 KiB
JavaScript

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.inviteAccept = exports.inviteMultiple = exports.invite = exports.tenantUserLookup = exports.find = exports.fetch = exports.search = exports.bulkDelete = exports.destroy = exports.countByApp = exports.adminUser = exports.bulkCreate = exports.save = void 0;
const constants_1 = require("../../../constants");
const redis_1 = require("../../../utilities/redis");
const email_1 = require("../../../utilities/email");
const sdk_1 = require("../../../sdk");
const environment_1 = __importDefault(require("../../../environment"));
const backend_core_1 = require("@budibase/backend-core");
const users_1 = require("../../../utilities/users");
const pro_1 = require("@budibase/pro");
const MAX_USERS_UPLOAD_LIMIT = 1000;
const save = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
try {
ctx.body = yield sdk_1.users.save(ctx.request.body);
}
catch (err) {
ctx.throw(err.status || 400, err);
}
});
exports.save = save;
const bulkCreate = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
let { users: newUsersRequested, groups } = ctx.request.body;
if (!environment_1.default.SELF_HOSTED && newUsersRequested.length > MAX_USERS_UPLOAD_LIMIT) {
ctx.throw(400, "Max limit for upload is 1000 users. Please reduce file size and try again.");
}
const db = backend_core_1.tenancy.getGlobalDB();
let groupsToSave = [];
if (groups.length) {
for (const groupId of groups) {
let oldGroup = yield db.get(groupId);
groupsToSave.push(oldGroup);
}
}
try {
let response = yield sdk_1.users.bulkCreate(newUsersRequested, groups);
yield pro_1.groups.bulkSaveGroupUsers(groupsToSave, response);
ctx.body = response;
}
catch (err) {
ctx.throw(err.status || 400, err);
}
});
exports.bulkCreate = bulkCreate;
const parseBooleanParam = (param) => {
return !(param && param === "false");
};
const adminUser = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const { email, password, tenantId } = ctx.request.body;
yield backend_core_1.tenancy.doInTenant(tenantId, () => __awaiter(void 0, void 0, void 0, function* () {
// account portal sends a pre-hashed password - honour param to prevent double hashing
const hashPassword = parseBooleanParam(ctx.request.query.hashPassword);
// account portal sends no password for SSO users
const requirePassword = parseBooleanParam(ctx.request.query.requirePassword);
if (yield backend_core_1.tenancy.doesTenantExist(tenantId)) {
ctx.throw(403, "Organisation already exists.");
}
const userExists = yield (0, users_1.checkAnyUserExists)();
if (userExists) {
ctx.throw(403, "You cannot initialise once an global user has been created.");
}
const user = {
email: email,
password: password,
createdAt: Date.now(),
roles: {},
builder: {
global: true,
},
admin: {
global: true,
},
tenantId,
};
try {
// always bust checklist beforehand, if an error occurs but can proceed, don't get
// stuck in a cycle
yield backend_core_1.cache.bustCache(backend_core_1.cache.CacheKeys.CHECKLIST);
const finalUser = yield sdk_1.users.save(user, {
hashPassword,
requirePassword,
});
// events
let account;
if (!environment_1.default.SELF_HOSTED && !environment_1.default.DISABLE_ACCOUNT_PORTAL) {
account = yield backend_core_1.accounts.getAccountByTenantId(tenantId);
}
yield backend_core_1.events.identification.identifyTenantGroup(tenantId, account);
ctx.body = finalUser;
}
catch (err) {
ctx.throw(err.status || 400, err);
}
}));
});
exports.adminUser = adminUser;
const countByApp = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const appId = ctx.params.appId;
try {
ctx.body = yield sdk_1.users.countUsersByApp(appId);
}
catch (err) {
ctx.throw(err.status || 400, err);
}
});
exports.countByApp = countByApp;
const destroy = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const id = ctx.params.id;
if (id === ctx.user._id) {
ctx.throw(400, "Unable to delete self.");
}
yield sdk_1.users.destroy(id, ctx.user);
ctx.body = {
message: `User ${id} deleted.`,
};
});
exports.destroy = destroy;
const bulkDelete = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const { userIds } = ctx.request.body;
if ((userIds === null || userIds === void 0 ? void 0 : userIds.indexOf(ctx.user._id)) !== -1) {
ctx.throw(400, "Unable to delete self.");
}
try {
let usersResponse = yield sdk_1.users.bulkDelete(userIds);
ctx.body = {
message: `${usersResponse.length} user(s) deleted`,
};
}
catch (err) {
ctx.throw(err);
}
});
exports.bulkDelete = bulkDelete;
const search = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const paginated = yield sdk_1.users.paginatedUsers(ctx.request.body);
// user hashed password shouldn't ever be returned
for (let user of paginated.data) {
if (user) {
delete user.password;
}
}
ctx.body = paginated;
});
exports.search = search;
// called internally by app server user fetch
const fetch = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const all = yield sdk_1.users.allUsers();
// user hashed password shouldn't ever be returned
for (let user of all) {
if (user) {
delete user.password;
}
}
ctx.body = all;
});
exports.fetch = fetch;
// called internally by app server user find
const find = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
ctx.body = yield sdk_1.users.getUser(ctx.params.id);
});
exports.find = find;
const tenantUserLookup = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const id = ctx.params.id;
const user = yield backend_core_1.tenancy.getTenantUser(id);
if (user) {
ctx.body = user;
}
else {
ctx.throw(400, "No tenant user found.");
}
});
exports.tenantUserLookup = tenantUserLookup;
const invite = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
let { email, userInfo } = ctx.request.body;
const existing = yield backend_core_1.users.getGlobalUserByEmail(email);
if (existing) {
ctx.throw(400, "Email address already in use.");
}
if (!userInfo) {
userInfo = {};
}
userInfo.tenantId = backend_core_1.tenancy.getTenantId();
const opts = {
subject: "{{ company }} platform invitation",
info: userInfo,
};
yield (0, email_1.sendEmail)(email, constants_1.EmailTemplatePurpose.INVITATION, opts);
ctx.body = {
message: "Invitation has been sent.",
};
yield backend_core_1.events.user.invited();
});
exports.invite = invite;
const inviteMultiple = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
let users = ctx.request.body;
let existing = false;
let existingEmail;
for (let user of users) {
if (yield backend_core_1.users.getGlobalUserByEmail(user.email)) {
existing = true;
existingEmail = user.email;
break;
}
}
if (existing) {
ctx.throw(400, `${existingEmail} already exists`);
}
for (let i = 0; i < users.length; i++) {
let userInfo = users[i].userInfo;
if (!userInfo) {
userInfo = {};
}
userInfo.tenantId = backend_core_1.tenancy.getTenantId();
const opts = {
subject: "{{ company }} platform invitation",
info: userInfo,
};
yield (0, email_1.sendEmail)(users[i].email, constants_1.EmailTemplatePurpose.INVITATION, opts);
}
ctx.body = {
message: "Invitations have been sent.",
};
});
exports.inviteMultiple = inviteMultiple;
const inviteAccept = (ctx) => __awaiter(void 0, void 0, void 0, function* () {
const { inviteCode, password, firstName, lastName } = ctx.request.body;
try {
// info is an extension of the user object that was stored by global
const { email, info } = yield (0, redis_1.checkInviteCode)(inviteCode);
ctx.body = yield backend_core_1.tenancy.doInTenant(info.tenantId, () => __awaiter(void 0, void 0, void 0, function* () {
const saved = yield sdk_1.users.save(Object.assign({ firstName,
lastName,
password,
email }, info));
const db = backend_core_1.tenancy.getGlobalDB();
const user = yield db.get(saved._id);
yield backend_core_1.events.user.inviteAccepted(user);
return saved;
}));
}
catch (err) {
if (err.code === backend_core_1.errors.codes.USAGE_LIMIT_EXCEEDED) {
// explicitly re-throw limit exceeded errors
ctx.throw(400, err);
}
ctx.throw(400, "Unable to create new user, invitation invalid.");
}
});
exports.inviteAccept = inviteAccept;