7fife-backend/controllers/user.controller.js

795 lines
24 KiB
JavaScript

// 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
};