LibreChat/api/models/User.js
Danny Avila e5336039fc
ci(backend-review.yml): add linter step to the backend review workflow (#625)
* ci(backend-review.yml): add linter step to the backend review workflow

* chore(backend-review.yml): remove prettier from lint-action configuration

* chore: apply new linting workflow

* chore(lint-staged.config.js): reorder lint-staged tasks for JavaScript and TypeScript files

* chore(eslint): update ignorePatterns in .eslintrc.js
chore(lint-action): remove prettier option in backend-review.yml
chore(package.json): add lint and lint:fix scripts

* chore(lint-staged.config.js): remove prettier --write command for js, jsx, ts, tsx files

* chore(titleConvo.js): remove unnecessary console.log statement
chore(titleConvo.js): add missing comma in options object

* chore: apply linting to all files

* chore(lint-staged.config.js): update lint-staged configuration to include prettier formatting
2023-07-14 09:36:49 -04:00

185 lines
3.8 KiB
JavaScript

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const Joi = require('joi');
const DebugControl = require('../utils/debug.js');
function log({ title, parameters }) {
DebugControl.log.functionName(title);
DebugControl.log.parameters(parameters);
}
const Session = mongoose.Schema({
refreshToken: {
type: String,
default: '',
},
});
const userSchema = mongoose.Schema(
{
name: {
type: String,
},
username: {
type: String,
lowercase: true,
required: [true, 'can\'t be blank'],
match: [/^[a-zA-Z0-9_-]+$/, 'is invalid'],
index: true,
},
email: {
type: String,
required: [true, 'can\'t be blank'],
lowercase: true,
unique: true,
match: [/\S+@\S+\.\S+/, 'is invalid'],
index: true,
},
emailVerified: {
type: Boolean,
required: true,
default: false,
},
password: {
type: String,
trim: true,
minlength: 8,
maxlength: 128,
},
avatar: {
type: String,
required: false,
},
provider: {
type: String,
required: true,
default: 'local',
},
role: {
type: String,
default: 'USER',
},
googleId: {
type: String,
unique: true,
sparse: true,
},
openidId: {
type: String,
unique: true,
sparse: true,
},
githubId: {
type: String,
unique: true,
sparse: true,
},
discordId: {
type: String,
unique: true,
sparse: true,
},
plugins: {
type: Array,
default: [],
},
refreshToken: {
type: [Session],
},
},
{ timestamps: true },
);
//Remove refreshToken from the response
userSchema.set('toJSON', {
transform: function (_doc, ret) {
delete ret.refreshToken;
return ret;
},
});
userSchema.methods.toJSON = function () {
return {
id: this._id,
provider: this.provider,
email: this.email,
name: this.name,
username: this.username,
avatar: this.avatar,
role: this.role,
emailVerified: this.emailVerified,
plugins: this.plugins,
createdAt: this.createdAt,
updatedAt: this.updatedAt,
};
};
userSchema.methods.generateToken = function () {
const token = jwt.sign(
{
id: this._id,
username: this.username,
provider: this.provider,
email: this.email,
},
process.env.JWT_SECRET,
{ expiresIn: eval(process.env.SESSION_EXPIRY) },
);
return token;
};
userSchema.methods.generateRefreshToken = function () {
const refreshToken = jwt.sign(
{
id: this._id,
username: this.username,
provider: this.provider,
email: this.email,
},
process.env.JWT_REFRESH_SECRET,
{ expiresIn: eval(process.env.REFRESH_TOKEN_EXPIRY) },
);
return refreshToken;
};
userSchema.methods.comparePassword = function (candidatePassword, callback) {
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
if (err) return callback(err);
callback(null, isMatch);
});
};
module.exports.hashPassword = async (password) => {
const hashedPassword = await new Promise((resolve, reject) => {
bcrypt.hash(password, 10, function (err, hash) {
if (err) reject(err);
else resolve(hash);
});
});
return hashedPassword;
};
module.exports.validateUser = (user) => {
log({
title: 'Validate User',
parameters: [{ name: 'Validate User', value: user }],
});
const schema = {
avatar: Joi.any(),
name: Joi.string().min(2).max(80).required(),
username: Joi.string()
.min(2)
.max(80)
.regex(/^[a-zA-Z0-9_-]+$/)
.required(),
password: Joi.string().min(8).max(128).allow('').allow(null),
};
return schema.validate(user);
};
const User = mongoose.model('User', userSchema);
module.exports = User;