Browse Source

feat(api): resend invite api

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/4134/head
Pranav C 2 years ago
parent
commit
4aca2992dc
  1. 174
      packages/nocodb/src/lib/meta/api/orgUserApis.ts

174
packages/nocodb/src/lib/meta/api/orgUserApis.ts

@ -1,56 +1,58 @@
import { Router } from 'express'
import { v4 as uuidv4 } from 'uuid'
import validator from 'validator'
import { OrgUserRoles } from '../../../enums/OrgUserRoles'
import Audit from '../../models/Audit'
import ProjectUser from '../../models/ProjectUser'
import SyncSource from '../../models/SyncSource'
import User from '../../models/User'
import Noco from '../../Noco'
import { metaApiMetrics } from '../helpers/apiMetrics'
import { NcError } from '../helpers/catchError'
import { extractProps } from '../helpers/extractProps'
import ncMetaAclMw from '../helpers/ncMetaAclMw'
import { PagedResponseImpl } from '../helpers/PagedResponse'
import { randomTokenString } from '../helpers/stringHelpers'
import { Tele } from 'nc-help'
import { sendInviteEmail } from './projectUserApis'
import { Router } from 'express';
import { PluginCategory } from 'nocodb-sdk';
import { v4 as uuidv4 } from 'uuid';
import validator from 'validator';
import { OrgUserRoles } from '../../../enums/OrgUserRoles';
import Audit from '../../models/Audit';
import ProjectUser from '../../models/ProjectUser';
import SyncSource from '../../models/SyncSource';
import User from '../../models/User';
import Noco from '../../Noco';
import { MetaTable } from '../../utils/globals';
import { metaApiMetrics } from '../helpers/apiMetrics';
import { NcError } from '../helpers/catchError';
import { extractProps } from '../helpers/extractProps';
import ncMetaAclMw from '../helpers/ncMetaAclMw';
import { PagedResponseImpl } from '../helpers/PagedResponse';
import { randomTokenString } from '../helpers/stringHelpers';
import { Tele } from 'nc-help';
import { sendInviteEmail } from './projectUserApis';
async function userList(req, res) {
res.json(
new PagedResponseImpl(await User.list(req.query), {
...req.query,
count: await User.count(req.query),
}),
)
})
);
}
async function userUpdate(req, res) {
const updateBody = extractProps(req.body, ['roles'])
const updateBody = extractProps(req.body, ['roles']);
const user = await User.get(req.params.userId)
const user = await User.get(req.params.userId);
if (user.roles.includes(OrgUserRoles.SUPER)) {
NcError.badRequest('Cannot update super admin roles')
NcError.badRequest('Cannot update super admin roles');
}
res.json(await User.update(req.params.userId, updateBody))
res.json(await User.update(req.params.userId, updateBody));
}
async function userDelete(req, res) {
const ncMeta = await Noco.ncMeta.startTransaction()
const ncMeta = await Noco.ncMeta.startTransaction();
try {
const user = await User.get(req.params.userId, ncMeta)
const user = await User.get(req.params.userId, ncMeta);
if (user.roles.includes(OrgUserRoles.SUPER)) {
NcError.badRequest('Cannot delete super admin')
NcError.badRequest('Cannot delete super admin');
}
// delete project user entry and assign to super admin
const projectUsers = await ProjectUser.getProjectsList(
req.params.userId,
ncMeta,
)
ncMeta
);
// TODO: assign super admin as project owner
for (const projectUser of projectUsers) {
@ -62,17 +64,17 @@ async function userDelete(req, res) {
}
// delete sync source entry
await SyncSource.deleteByUserId(req.params.userId, ncMeta)
await SyncSource.deleteByUserId(req.params.userId, ncMeta);
// delete user
await User.delete(req.params.userId, ncMeta)
await User.delete(req.params.userId, ncMeta);
await ncMeta.commit()
await ncMeta.commit();
} catch (e) {
await ncMeta.rollback(e)
await ncMeta.rollback(e);
}
res.json(await User.delete(req.params.userId))
res.json(await User.delete(req.params.userId));
}
async function userAdd(req, res, next) {
@ -81,34 +83,34 @@ async function userAdd(req, res, next) {
req.body.roles &&
![OrgUserRoles.VIEWER, OrgUserRoles.CREATOR].includes(req.body.roles)
) {
NcError.badRequest('Invalid role')
NcError.badRequest('Invalid role');
}
// extract emails from request body
const emails = (req.body.email || '')
.toLowerCase()
.split(/\s*,\s*/)
.map((v) => v.trim())
.map((v) => v.trim());
// check for invalid emails
const invalidEmails = emails.filter((v) => !validator.isEmail(v))
const invalidEmails = emails.filter((v) => !validator.isEmail(v));
if (!emails.length) {
return NcError.badRequest('Invalid email address')
return NcError.badRequest('Invalid email address');
}
if (invalidEmails.length) {
NcError.badRequest('Invalid email address : ' + invalidEmails.join(', '))
NcError.badRequest('Invalid email address : ' + invalidEmails.join(', '));
}
const invite_token = uuidv4()
const error = []
const invite_token = uuidv4();
const error = [];
for (const email of emails) {
// add user to project if user already exist
const user = await User.getByEmail(email)
const user = await User.getByEmail(email);
if (user) {
NcError.badRequest('User already exist')
NcError.badRequest('User already exist');
} else {
try {
// create new user with invite token
@ -118,35 +120,34 @@ async function userAdd(req, res, next) {
email,
roles: OrgUserRoles.VIEWER,
token_version: randomTokenString(),
})
});
const count = await User.count()
Tele.emit('evt', { evt_type: 'org:user:invite', count })
const count = await User.count();
Tele.emit('evt', { evt_type: 'org:user:invite', count });
await Audit.insert({
project_id: req.params.projectId,
op_type: 'AUTHENTICATION',
op_type: 'ORG_USER',
op_sub_type: 'INVITE',
user: req.user.email,
description: `invited ${email} to ${req.params.projectId} project `,
ip: req.clientIp,
})
});
// in case of single user check for smtp failure
// and send back token if failed
if (
emails.length === 1 &&
!(await sendInviteEmail(email, invite_token, req))
) {
return res.json({ invite_token, email })
return res.json({ invite_token, email });
} else {
sendInviteEmail(email, invite_token, req)
sendInviteEmail(email, invite_token, req);
}
} catch (e) {
console.log(e)
console.log(e);
if (emails.length === 1) {
return next(e)
return next(e);
} else {
error.push({ email, error: e.message })
error.push({ email, error: e.message });
}
}
}
@ -155,31 +156,74 @@ async function userAdd(req, res, next) {
if (emails.length === 1) {
res.json({
msg: 'success',
})
});
} else {
return res.json({ invite_token, emails, error })
return res.json({ invite_token, emails, error });
}
}
async function userInviteResend(req, res): Promise<any> {
const user = await User.get(req.params.userId);
if (!user) {
NcError.badRequest(`User with id '${req.params.userId}' not found`);
}
const invite_token = uuidv4();
await User.update(user.id, {
invite_token,
invite_token_expires: new Date(Date.now() + 24 * 60 * 60 * 1000),
});
const pluginData = await Noco.ncMeta.metaGet2(null, null, MetaTable.PLUGIN, {
category: PluginCategory.EMAIL,
active: true,
});
if (!pluginData) {
NcError.badRequest(
`No Email Plugin is found. Please go to App Store to configure first or copy the invitation URL to users instead.`
);
}
await sendInviteEmail(user.email, invite_token, req);
await Audit.insert({
op_type: 'ORG_USER',
op_sub_type: 'RESEND_INVITE',
user: user.email,
description: `resent a invite to ${user.email} `,
ip: req.clientIp,
});
res.json({ msg: 'success' });
}
const router = Router({ mergeParams: true })
const router = Router({ mergeParams: true });
router.get(
'/api/v1/users',
metaApiMetrics,
ncMetaAclMw(userList, 'userList', [OrgUserRoles.SUPER]),
)
ncMetaAclMw(userList, 'userList', [OrgUserRoles.SUPER])
);
router.patch(
'/api/v1/users/:userId',
metaApiMetrics,
ncMetaAclMw(userUpdate, 'userUpdate', [OrgUserRoles.SUPER]),
)
ncMetaAclMw(userUpdate, 'userUpdate', [OrgUserRoles.SUPER])
);
router.delete(
'/api/v1/users/:userId',
metaApiMetrics,
ncMetaAclMw(userDelete, 'userAdd', [OrgUserRoles.SUPER]),
)
ncMetaAclMw(userDelete, 'userAdd', [OrgUserRoles.SUPER])
);
router.post(
'/api/v1/users',
metaApiMetrics,
ncMetaAclMw(userAdd, 'userDelete', [OrgUserRoles.SUPER]),
)
export default router
ncMetaAclMw(userAdd, 'userDelete', [OrgUserRoles.SUPER])
);
router.post(
'/api/v1/users/:userId/resend-invite',
metaApiMetrics,
ncMetaAclMw(userInviteResend, 'userInviteResend', [OrgUserRoles.SUPER])
);
export default router;

Loading…
Cancel
Save