mirror of
https://github.com/directus/directus.git
synced 2026-01-24 13:28:15 -05:00
Setup invite user endpoint
This commit is contained in:
@@ -40,6 +40,7 @@ EXTENSIONS_PATH="./extensions"
|
||||
####################################################################################################
|
||||
# Email
|
||||
|
||||
EMAIL_FROM="no-reply@directus.io"
|
||||
EMAIL_TRANSPORT="sendmail"
|
||||
|
||||
## Email (Sendmail Transport)
|
||||
|
||||
@@ -7,7 +7,10 @@ import { promisify } from 'util';
|
||||
|
||||
const readFile = promisify(fs.readFile);
|
||||
|
||||
const liquidEngine = new Liquid();
|
||||
const liquidEngine = new Liquid({
|
||||
root: path.resolve(__dirname, 'templates'),
|
||||
extname: '.liquid',
|
||||
});
|
||||
|
||||
logger.trace('[Email] Initializing email transport...');
|
||||
|
||||
@@ -52,6 +55,7 @@ if (emailTransport === 'sendmail') {
|
||||
|
||||
export type EmailOptions = {
|
||||
to: string; // email address of the recipient
|
||||
from: string;
|
||||
subject: string;
|
||||
text: string;
|
||||
html: string;
|
||||
@@ -61,6 +65,8 @@ export default async function sendMail(options: EmailOptions) {
|
||||
const templateString = await readFile(path.join(__dirname, 'templates/base.liquid'), 'utf8');
|
||||
const html = await liquidEngine.parseAndRender(templateString, { html: options.html });
|
||||
|
||||
options.from = options.from || process.env.EMAIL_FROM;
|
||||
|
||||
try {
|
||||
await transporter.sendMail({ ...options, html: html });
|
||||
} catch (error) {
|
||||
@@ -68,3 +74,13 @@ export default async function sendMail(options: EmailOptions) {
|
||||
logger.warn(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function sendInviteMail(email: string, url: string) {
|
||||
/**
|
||||
* @TODO pull this from directus_settings
|
||||
*/
|
||||
const projectName = 'directus';
|
||||
|
||||
const html = await liquidEngine.renderFile('user-invitation', { email, url, projectName });
|
||||
await transporter.sendMail({ from: process.env.EMAIL_FROM, to: email, html: html });
|
||||
}
|
||||
|
||||
15
src/mail/templates/user-invitation.liquid
Normal file
15
src/mail/templates/user-invitation.liquid
Normal file
@@ -0,0 +1,15 @@
|
||||
{% layout "base" %}
|
||||
{% block content %}
|
||||
|
||||
<p>You have been invited to {{ projectName }}. Please click the link below to join:</p>
|
||||
|
||||
<p><a href="url">{{ url }}</a></p>
|
||||
|
||||
{% comment %}
|
||||
@TODO
|
||||
Make this white-labeled
|
||||
{% endcomment %}
|
||||
|
||||
<p>Love,<br>Directus</p>
|
||||
|
||||
{% endblock %}
|
||||
@@ -3,6 +3,7 @@ import asyncHandler from 'express-async-handler';
|
||||
import sanitizeQuery from '../middleware/sanitize-query';
|
||||
import validateQuery from '../middleware/validate-query';
|
||||
import * as UsersService from '../services/users';
|
||||
import Joi from '@hapi/joi';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -14,6 +15,20 @@ router.post(
|
||||
})
|
||||
);
|
||||
|
||||
const inviteSchema = Joi.object({
|
||||
email: Joi.string().email().required(),
|
||||
role: Joi.string().uuid({ version: 'uuidv4' }).required(),
|
||||
});
|
||||
|
||||
router.post(
|
||||
'/invite',
|
||||
asyncHandler(async (req, res) => {
|
||||
await inviteSchema.validateAsync(req.body);
|
||||
await UsersService.inviteUser(req.body.email, req.body.role);
|
||||
res.end();
|
||||
})
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/',
|
||||
sanitizeQuery,
|
||||
|
||||
@@ -1,22 +1,34 @@
|
||||
import { Query } from '../types/query';
|
||||
import * as ItemsService from './items';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { sendInviteMail } from '../mail';
|
||||
|
||||
export const createUser = async (data: Record<string, any>, query: Query) => {
|
||||
export const createUser = async (data: Record<string, any>, query?: Query) => {
|
||||
return await ItemsService.createItem('directus_users', data, query);
|
||||
};
|
||||
|
||||
export const readUsers = async (query: Query) => {
|
||||
export const readUsers = async (query?: Query) => {
|
||||
return await ItemsService.readItems('directus_users', query);
|
||||
};
|
||||
|
||||
export const readUser = async (pk: string | number, query: Query) => {
|
||||
export const readUser = async (pk: string | number, query?: Query) => {
|
||||
return await ItemsService.readItem('directus_users', pk, query);
|
||||
};
|
||||
|
||||
export const updateUser = async (pk: string | number, data: Record<string, any>, query: Query) => {
|
||||
export const updateUser = async (pk: string | number, data: Record<string, any>, query?: Query) => {
|
||||
return await ItemsService.updateItem('directus_users', pk, data, query);
|
||||
};
|
||||
|
||||
export const deleteUser = async (pk: string | number) => {
|
||||
await ItemsService.deleteItem('directus_users', pk);
|
||||
};
|
||||
|
||||
export const inviteUser = async (email: string, role: string) => {
|
||||
await createUser({ email, role, status: 'invited' });
|
||||
|
||||
const payload = { email };
|
||||
const token = jwt.sign(payload, process.env.SECRET, { expiresIn: '7d' });
|
||||
const acceptURL = process.env.PUBLIC_URL + '/admin/accept-invite?token=' + token;
|
||||
|
||||
await sendInviteMail(email, acceptURL);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user