262 lines
10 KiB
JavaScript
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;
|