// const User = require('../models/user.model'); const jwt = require('jsonwebtoken'); const authConfig = require('../configs/auth.config'); const bcrypt = require('bcryptjs'); const constant = require('../util/constant'); const Artist = require('../models/artist.model'); const Reward = require('../models/Reward.model'); const Song = require('../models/song.model'); const axios = require('axios'); const { User } = require('../models/user.model'); const { validationResult } = require('express-validator'); const nodemailer = require('nodemailer'); const sendOTPByEmail = async (email, otp) => { try { const transporter = nodemailer.createTransport({ service: 'gmail', // e.g., 'Gmail' auth: { user: 'ay2087355@gmail.com', pass: 'mqqqnoutaukxenlh' } }); // Send OTP email await transporter.sendMail({ from: 'checkdemo02@gmail.com', to: email, subject: 'Your OTP Code', text: `Your OTP code is: ${otp}` }); console.log('OTP email sent successfully'); } catch (error) { console.error('Error sending OTP email:', error); throw new Error('Failed to send OTP email'); } }; const userRegister = async (req, res) => { try { // Check if the email already exists const existingUser = await User.findOne({ email: req.body.email }); console.log("🚀 ~ userRegister ~ existingUser:", existingUser) if (existingUser) { return res.status(400).json({ error_code: 400, message: 'Email already exists' }); } // Generate OTP const otp = Math.floor(10000 + Math.random() * 90000); // Create user object with hashed password const user = await User.create({ email: req.body.email, password: bcrypt.hashSync(req.body.password, 8), registerWith: constant.registerWith.Email, otp: otp, userName: req.body.userName, userType: constant.userTypes.customer }); console.log("🚀 ~ userRegister ~ user:", user) // Send OTP email await sendOTPByEmail(user.email, otp); return res.status(200).json({ error_code: 200, message: 'Success', user: user }); } catch (err) { console.error('Error in user registration:', err); return res.status(500).json({ error_code: 500, message: 'Failed' }); } }; //otp verify const verifyOTP = async (req, res) => { try { const { email, otp } = req.body; const user = await User.findOne({ email }); if (!user) { return res.status(400).json({ error_code: 400, message: 'User not found' }); } if (user.otp !== otp) { return res.status(400).json({ error_code: 400, message: 'Incorrect OTP' }); } user.otpVerified = true; await user.save(); return res.status(200).json({ error_code: 200, message: 'OTP verified successfully', }); } catch (error) { console.error('Error in verify OTP:', error); return res.status(500).json({ error_code: 500, message: 'Failed' }); } }; const createGoogle = async (req, res) => { try { // Validate request body const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } // Fetch user data from Google API using access token const response = await axios.get(`https://www.googleapis.com/oauth2/v1/userinfo?access_token=${req.body.accessToken}`); const userData = response.data; // Check if the user with this Google ID already exists let user = await User.findOne({ googleId: userData.id }); // If user with Google ID doesn't exist, check by email if (!user) { user = await User.findOne({ email: userData.email }); } // If user exists, generate token and return response if (user) { const token = jwt.sign({ id: user._id, userType: user.userType }, process.env.JWT_SECRET, { expiresIn: '1h' }); return res.status(200).json({ _id: user._id, email: user.email, token: token, userType: user.userType, status: user.status, message: 'User logged in successfully' }); } // If user doesn't exist, create a new user const newUser = await User.create({ email: userData.email, name: userData.name, profilePic: userData.picture, authenticationType: "GOOGLE", googleId: userData.id, }); // Generate token for the new user const token = jwt.sign({ id: newUser._id, userType: newUser.userType }, process.env.JWT_SECRET, { expiresIn: '1h' }); // Send response with user data return res.status(201).json({ _id: newUser._id, email: newUser.email, token: token, userType: newUser.userType, authenticationType: "GOOGLE", status: newUser.status, message: 'New user created and logged in successfully' }); } catch (error) { // Handle errors console.error('Error inside createGoogle:', error); return res.status(500).json({ error_code: 500, message: 'Internal Server Error' }); } }; const update = async (req, res) => { try { let id = req.params.id; let obj = { userName: req.body.userName ? req.body.userName : undefined, email: req.body.email ? req.body.email : undefined, password: req.body.password ? bcrypt.hashSync(req.body.password) : undefined, } if (req.files.length > 0) { obj['image'] = { fileName: req.files[0].filename, fileAddress: req.files[0].path } } const user = await User.findById(id); const admin = await User.findById(req.userId); if (req.body.status) { if (admin.userTypes == constant.userTypes.admin) { obj.status = req.body.status ? req.body.status : undefined; } else { return res.status(401).send({ error_code: 400, message: 'status can only be updated by admin' }) } } console.log(`object for updation of user is ${obj}`); await user.updateOne(obj) await user.save(); return res.status(201).send({ error_code: 200, message: "User updated Successssssfully" }) } catch (err) { console.log(err); res.status(500).send({ error_code: 500, message: 'Error in update controller ' }) } } const passUpCreate = async (req, res) => { console.log(req.body.email); try { let email = req.body.email function generateRandomNumber() { const min = 100000; // Minimum value (inclusive) const max = 999999; // Maximum value (inclusive) const randomNumber = Math.floor(Math.random() * (max - min + 1)) + min; const uppercaseLetter = String.fromCharCode(Math.floor(Math.random() * 26) + 65); // Uppercase letter ASCII range: 65-90 const lowercaseLetter = String.fromCharCode(Math.floor(Math.random() * 26) + 97); // Lowercase letter ASCII range: 97-122 const specialCharacter = String.fromCharCode(Math.floor(Math.random() * 15) + 33); // Special character ASCII range: 33-47 const randomString = randomNumber.toString() + uppercaseLetter + lowercaseLetter + specialCharacter; // Shuffle the characters in the string const shuffledString = randomString.split('').sort(() => 0.5 - Math.random()).join(''); return shuffledString; } // Usage example const TempPassword = generateRandomNumber(); let obj = { password: bcrypt.hashSync(TempPassword) } const user = await User.findOneAndUpdate({ email: email }, { $set: obj }); user.save(); return res.status(201).send({ error_code: 200, message: `Temporary Password is ${TempPassword} for this ${email}` }) } catch (err) { console.log(err); return res.status(500).send({ error_code: 500, message: 'Error in passUpCreate' }) } } const createFacebook = async (req, res) => { try { let user = await User.findOne({ email: req.body.email }); var flag = 0; if (!user) { let obj = { email: req.body.email, registerWith: constant.registerWith.facebook } user = await User.create(obj); flag = 1 } if (user.registerWith != constant.registerWith.facebook) { return res.status(400).send({ error_code: 400, message: "Can't login Through facebook" }); } let str = flag ? 'User Got Created' : 'User was already Created'; const token = jwt.sign({ id: user._id }, authConfig.secretKey, { expiresIn: 600000 }); return res.status(201).send({ error_code: 200, message: str, acessToken: token }) } catch (err) { console.log(err); return res.status(500).send({ error_code: 500, message: 'Error in creating user' }) } } const deleteUser = async (req, res) => { try { let id = req.params.id; await User.deleteOne({ _id: id }); return res.status(201).send({ error_code: 200, message: 'User Deleted succefully' }) } catch (err) { console.log('Error inside delete User controller', err); return res.status(500).send({ error_code: 500, message: 'internal server error' }) } } const getUserPlaylist = async (req, res) => { try { const user = await User.findById(req.userId).populate('playlist'); console.log(user); return res.status(201).send(constant.arrayConverterName(user.playlist)); } catch (err) { console.log('Error inside getUserPlaylist Controller', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } const favrioteSong = async (req, res) => { try { const user = await User.findById(req.userId).populate('favrioteSongs'); console.log(user); for (let i = 0; i < user.favrioteSongs.length; i++) { if (user.favrioteSongs[i]._id == req.params.id) { await user.updateOne({ $pull: { favrioteSongs: req.params.id } }); await user.save(); return res.status(201).send({ error_code: 200, message: 'Song got removed from favrioteSong' }) } } user.favrioteSongs.push(req.params.id); await user.save(); return res.status(201).send({ error_code: 200, message: 'Song got added to favrioteSong' }) } catch (err) { console.log('Error inside favrioteSong Controller', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } const getfavrioteSongs = async (req, res) => { try { const user = await User.findById(req.userId).populate('favrioteSongs'); return res.status(200).send(user.favrioteSongs); } catch (err) { console.log('Error inside getFavrioteSong Controller', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } const PlayedSong = async (req, res) => { try { let key = req.params.id; let userId = req.userId; const user = await User.findById(userId); if (user.mostPlayedSongs[key]) { const updatedObj = { $set: { ['mostPlayedSongs.' + key]: (++user.mostPlayedSongs[key]) } } await User.findByIdAndUpdate(userId, updatedObj); } else { const updatedObj = { $set: { ['mostPlayedSongs.' + key]: 1 } } console.log('not hello') await User.findByIdAndUpdate(userId, updatedObj) } return res.status(201).send({ error_code: 200, message: 'Song is Played ' }) } catch (err) { console.log('Error inside playedSong', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } const getmostPlayedSong = async (req, res) => { try { const user = await User.findById(req.userId) console.log(user.mostPlayedSongs); // Convert the object to an array of key-value pairs const objEntries = Object.entries(user.mostPlayedSongs); // Sort the Array objEntries.sort((a, b) => b[1] - a[1]); // Convert the sorted array back to an object const sortedObj = Object.fromEntries(objEntries); return res.status(201).send(sortedObj); } catch (err) { console.log('Error inside mostPlayedSong', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } const followingArtist = async (req, res) => { try { const artistId = req.params.id; const userId = req.userId; const user = await User.findById(userId); const artist = await Artist.findById(artistId); for (let i = 0; i < user.following.length; i++) { if (user.following[i] == artistId) { user.following.pull(artistId); await user.save(); artist.followers.pull(userId); await artist.save(); return res.status(201).send({ message: `You Unfollowed ${artist.name}` }) } } user.following.push(artistId); await user.save(); artist.followers.push(userId); await artist.save(); return res.status(200).send({ error_code: 200, message: `you followed ${artist.name}` }) } catch (err) { console.log('Error inside following Controller', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } // Function to calculate word alignment accuracy using Levenshtein distance // Function to calculate timing accuracy // Function to evaluate word alignment accuracy and timing accuracy const evaluateAccuracy = async (req, res) => { try { const song = await Song.findById(req.params.id); const recognizedLyrics = req.recognizedLyrics; const originalLyrics = song.lyricsTimeStamp; const wordAlignmentAccuracy = constant.calculateWordAlignmentAccuracy(recognizedLyrics, originalLyrics); const timingAccuracy = constant.calculateTimingAccuracy(recognizedLyrics, originalLyrics); const totalAccuracy = (wordAlignmentAccuracy.toFixed(2) + timingAccuracy.toFixed(2)) / 2; console.log(totalAccuracy); var reward; switch (totalAccuracy) { case (totalAccuracy > 90): reward = 'A+'; break; case (totalAccuracy > 80): reward = 'A' break; case (totalAccuracy > 70): reward = 'B+' break; case (totalAccuracy > 60): reward = 'B' break; case (totalAccuracy > 50): reward = 'C+' break; case (totalAccuracy > 40): reward = 'C' break; case (totalAccuracy < 40): reward = 'F' break; } const reward_score = await Reward.find({ score: reward }); const user = await User.findById(req.userId); user.score += reward_score.reward; await user.save(); console.log(user); return res.status(201).send({ error_code: 200, Score: reward }) } catch (err) { console.log('Error inside EvaluateAccuracy Controller', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } const ranking = async (req, res) => { try { const ranking = await User.find({}).sort({ score: -1 }).limit(5); return res.status(201).send(ranking); } catch (err) { console.log('Error inside Ranking Controller', err); return res.status(500).send({ error_code: 500, message: 'Internal Server Error' }) } } const changeUserStatus = async (req, res) => { try { const { id } = req.params; const { status } = req.body; // Validate the status value if (!['activate', 'deactivate'].includes(status)) { return res.status(400).send({ error_code: 400, message: 'Invalid status value. Status must be either "activate" or "deactivate".' }); } const user = await User.findById(id); if (!user) { return res.status(404).send({ error_code: 404, message: 'User not found.' }); } user.status = status; await user.save(); return res.status(200).send({ error_code: 200, message: `User status updated to ${status} successfully.` }); } catch (err) { console.log('Error inside changeStatus controller', err); return res.status(500).send({ error_code: 500, message: 'Internal server error.' }); } } const usergetAllSongs =async(req,res)=>{ try { const song = await Song.find({status: 'Active'}); return res.status(200).send(song); }catch (err) { console.log('Error inside changeStatus controller', err); return res.status(500).send({ error_code: 500, message: 'Internal server error.' }); } } const newRelease = async (req, res) => { try { const fiveDaysAgo = new Date(); fiveDaysAgo.setDate(fiveDaysAgo.getDate() - 3); const songs = await Song.find({ status: 'activate', createdAt: { $gte: fiveDaysAgo } }); return res.status(200).send({error_code:200,message:'new realese songs',song:songs}); } catch (err) { console.log('Error inside newRelease controller', err); return res.status(500).send({ error_code: 500, message: 'Internal server error.' }); } } const homeData = async (req, res) => { try { // Pipeline to aggregate songs with category name, artist names, and image URL const pipeline = [ { $match: { status: 'activate' } }, { $lookup: { from: 'categories', localField: 'categoryId', foreignField: '_id', as: 'category' } }, { $lookup: { from: 'artists', localField: 'artistId', foreignField: '_id', as: 'artists' } }, { $group: { _id: { categoryId: '$categoryId', categoryName: '$category.name' }, songs: { $push: { _id: '$_id', title: '$title', artistNames: '$artists.ArtistName', imageUrl: '$coverArtImage.imageUrl' } } } }, { $project: { _id: 0, categoryName: '$_id.categoryName', songs: { $map: { input: '$songs', as: 'song', in: { _id: '$$song._id', title: '$$song.title', artistNames: '$$song.artistNames', imageUrl: '$$song.imageUrl' } } } } } ]; const categoriesWithSongs = await Song.aggregate(pipeline); return res.status(200).json({ error_code: 200, message: 'Songs grouped by category retrieved successfully', categories: categoriesWithSongs }); } catch (err) { // Log and handle errors console.error('Error inside homeData:', err); return res.status(500).json({ error_code: 500, message: 'Internal server error' }); } }; const artistData = async (req, res) => { try { const pipeline = [ { $lookup: { from: 'songs', localField: '_id', foreignField: 'artistId', as: 'songs' } }, { $project: { _id: 1, ArtistName: 1, songs: { $map: { input: '$songs', as: 'song', in: { _id: '$$song._id', title: '$$song.title', status: '$$song.status', imageUrl: '$$song.coverArtImage.imageUrl' } } } } } ]; // Execute aggregation pipeline const artistsWithSongs = await Artist.aggregate(pipeline); // Return response return res.status(200).json({ error_code: 200, message: 'Artist data with songs retrieved successfully', artists: artistsWithSongs }); } catch (error) { // Log and handle errors console.error('Error inside artistData:', error); return res.status(500).json({ error_code: 500, message: 'Internal server error' }); } }; module.exports = { userRegister, verifyOTP, createGoogle, createFacebook, update, passUpCreate, getUserPlaylist, favrioteSong, deleteUser, PlayedSong, getmostPlayedSong, getfavrioteSongs, followingArtist, evaluateAccuracy, ranking, changeUserStatus,usergetAllSongs, newRelease, homeData, artistData };