📩 feat: invite user (#3012)

* feat: basic invite-user script

* feat: add invite user functionality and registration validation middleware

* fix: invite user fixes

* refactor: consolidate direct model access to a central place of functions

* style(Registration): add spinner to continue button

* refactor: import ordrer

* feat: improve invite user script and error handling

* fix: merge conflict

* refactor: remove `console.log` and use `logger`

* fix: token operation and checkinvite issues

* bring back comment and remove console log

* fix: return invalid token when token is not found

* fix: getInvite fix

* refactor: Update Token.js to use async/await syntax for update and delete operations

* feat: Refactor Token.js to use async/await syntax for createToken and findToken functions

* refactor(inviteUser): define functions outside of module.exports

* Update AuthService.js

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Marco Beretta 2024-08-18 06:23:38 +02:00 committed by GitHub
parent a45b384bbc
commit bbb9324447
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 695 additions and 61 deletions

91
config/invite-user.js Normal file
View file

@ -0,0 +1,91 @@
const path = require('path');
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
const { sendEmail, checkEmailConfig } = require('~/server/utils');
const { askQuestion, silentExit } = require('./helpers');
const { createInvite } = require('~/models/inviteUser');
const User = require('~/models/User');
const connect = require('./connect');
(async () => {
await connect();
console.purple('--------------------------');
console.purple('Invite a new user account!');
console.purple('--------------------------');
if (process.argv.length < 5) {
console.orange('Usage: npm run invite-user <email>');
console.orange('Note: if you do not pass in the arguments, you will be prompted for them.');
console.purple('--------------------------');
}
// Check if email service is enabled
if (!checkEmailConfig()) {
console.red('Error: Email service is not enabled!');
silentExit(1);
}
// Get the email of the user to be invited
let email = '';
if (process.argv.length >= 3) {
email = process.argv[2];
}
if (!email) {
email = await askQuestion('Email:');
}
// Validate the email
if (!email.includes('@')) {
console.red('Error: Invalid email address!');
silentExit(1);
}
// Check if the user already exists
const userExists = await User.findOne({ email });
if (userExists) {
console.red('Error: A user with that email already exists!');
silentExit(1);
}
const token = await createInvite(email);
const inviteLink = `${process.env.DOMAIN_CLIENT}/register?token=${token}`;
const appName = process.env.APP_TITLE || 'LibreChat';
if (!checkEmailConfig()) {
console.green('Send this link to the user:', inviteLink);
silentExit(0);
}
try {
await sendEmail({
email: email,
subject: `Invite to join ${appName}!`,
payload: {
appName: appName,
inviteLink: inviteLink,
year: new Date().getFullYear(),
},
template: 'inviteUser.handlebars',
});
} catch (error) {
console.error('Error: ' + error.message);
silentExit(1);
}
// Done!
console.green('Invitation sent successfully!');
silentExit(0);
})();
process.on('uncaughtException', (err) => {
if (!err.message.includes('fetch failed')) {
console.error('There was an uncaught error:');
console.error(err);
}
if (err.message.includes('fetch failed')) {
return;
} else {
process.exit(1);
}
});