const { db } = require('../db'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const crypto = require('crypto'); class User { constructor(userData) { Object.assign(this, userData); this.id = userData._id; // Alias _id to id } static findOne(query) { const chain = { select: function(fields) { return this; }, then: function(resolve, reject) { return new Promise((res, rej) => { db.users.findOne(query, (err, doc) => { if (err) rej(err); else res(doc ? new User(doc) : null); }); }).then(resolve, reject); }, catch: function(reject) { return this.then(null, reject); } }; return chain; } static async findById(id) { return new Promise((resolve, reject) => { db.users.findOne({ _id: id }, (err, doc) => { if (err) reject(err); else resolve(doc ? new User(doc) : null); }); }); } static async create(userData) { const salt = await bcrypt.genSalt(10); if (userData.password) { userData.password = await bcrypt.hash(userData.password, salt); } userData.usage = userData.usage || { requestsToday: 0, lastRequestDate: new Date() }; userData.createdAt = userData.createdAt || new Date(); userData.role = userData.role || 'user'; const owners = ['johanvoncd7@gmail.com', 'codexai@mightysmp.online']; if (owners.includes(userData.email)) { userData.role = 'owner'; } return new Promise((resolve, reject) => { db.users.insert(userData, (err, newDoc) => { if (err) reject(err); else resolve(new User(newDoc)); }); }); } static async findByIdAndUpdate(id, update) { return new Promise((resolve, reject) => { db.users.update({ _id: id }, { $set: update }, { returnUpdatedDocs: true }, (err, numReplaced, affectedDoc) => { if (err) reject(err); else resolve(affectedDoc ? new User(affectedDoc) : null); }); }); } async matchPassword(enteredPassword) { return await bcrypt.compare(enteredPassword, this.password); } getSignedJwtToken() { return jwt.sign({ id: this._id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRE }); } getResetPasswordToken() { const resetToken = crypto.randomBytes(20).toString('hex'); this.resetPasswordToken = crypto.createHash('sha256').update(resetToken).digest('hex'); this.resetPasswordExpire = Date.now() + 10 * 60 * 1000; return resetToken; } async save() { return new Promise((resolve, reject) => { const data = { ...this }; const id = data._id; delete data._id; db.users.update({ _id: id }, { $set: data }, { upsert: true }, (err) => { if (err) reject(err); else resolve(this); }); }); } } module.exports = User;