349 lines
15 KiB
JavaScript
349 lines
15 KiB
JavaScript
import { catchAsyncAction, generateToken, makeResponse } from "../../helper/index.js";
|
|
import { responseMessages, statusCodes } from '../../helper/makeResponse/index.js';
|
|
import { addUserAnswersByUserId, addUserDrillsByUserId, createQuestions, getAllQuestions, getQuestionById, getUserAnswersByUserId, getUserTrainingByUserId, updateQuestionById } from "../../services/assessment.js";
|
|
import { getUserById } from "../../services/users.js";
|
|
import { privateKey } from "../../config/privateKeys.js";
|
|
import axios from "axios";
|
|
/**
|
|
* API handler to add assessment questions.
|
|
* Validates input and creates new questions in the database.
|
|
*
|
|
* @param {Object} req - The request object containing assessment questions.
|
|
* @param {Object} res - The response object used to send responses back to the client.
|
|
* @returns {Object} - A response object indicating the success or failure of the operation.
|
|
*/
|
|
export const addAssessmentQuestions = catchAsyncAction(async (req, res) => {
|
|
const questions = req.body.assessment; // Extracting assessment questions from the request body
|
|
|
|
// Input validation: ensure the array is not empty
|
|
if (!Array.isArray(questions) || questions.length === 0) {
|
|
return makeResponse(res, statusCodes.BAD_REQUEST, false, 'Request body must be an array of questions.', {});
|
|
}
|
|
|
|
|
|
for (const questionData of questions) {
|
|
const { question } = questionData; // Destructuring question from questionData
|
|
|
|
// Validate that all necessary fields are present
|
|
if (!question) {
|
|
return makeResponse(res, statusCodes.BAD_REQUEST, false, 'All fields are required.', {});
|
|
}
|
|
questionData.options = JSON.stringify(questionData.options || []); // Stringify options if they exist
|
|
}
|
|
|
|
try {
|
|
const questionData = await createQuestions(questions); // Create questions in the database
|
|
|
|
return makeResponse(res, statusCodes.SUCCESS, true, responseMessages.QUESTIONS_CREATED, questionData);
|
|
} catch (error) {
|
|
const code = error?.code || statusCodes.SERVER_ERROR;
|
|
const message = error?.message || responseMessages.SOMETHING_WRONG;
|
|
|
|
return makeResponse(res, code, false, message, {});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* API handler to update an assessment question by its ID.
|
|
* Validates input and updates the question in the database.
|
|
*
|
|
* @param {Object} req - The request object containing the question ID and updated data.
|
|
* @param {Object} res - The response object used to send responses back to the client.
|
|
* @returns {Object} - A response object indicating the success or failure of the operation.
|
|
*/
|
|
export const updateAssessmentQuestionById = catchAsyncAction(async (req, res) => {
|
|
const { id } = req.params; // Get the question id from the URL
|
|
const { question, options, orderId } = req.body; // Get the updated data from the request body
|
|
|
|
try {
|
|
// Find the question by ID
|
|
const foundQuestion = await getQuestionById(id);
|
|
|
|
if (!foundQuestion) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, responseMessages.QUESTIONS_NOT_FOUND, {});
|
|
}
|
|
|
|
// Update the question with new data
|
|
foundQuestion.question = question || foundQuestion.question; // Update question if provided
|
|
foundQuestion.options = JSON.stringify(options) || foundQuestion.options; // Update options if provided
|
|
foundQuestion.orderId = orderId || foundQuestion.orderId; // Update orderId if provided
|
|
|
|
await updateQuestionById(foundQuestion); // Save the updated question
|
|
|
|
return makeResponse(res, statusCodes.SUCCESS, true, responseMessages.QUESTIONS_UPDATED, foundQuestion); // Return success response
|
|
|
|
} catch (error) {
|
|
const code = error?.code || statusCodes.SERVER_ERROR;
|
|
const message = error?.message || responseMessages.SOMETHING_WRONG;
|
|
|
|
return makeResponse(res, code, false, message, {});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* API handler to get all assessment questions.
|
|
* Fetches all questions from the database and returns them.
|
|
*
|
|
* @param {Object} req - The request object.
|
|
* @param {Object} res - The response object used to send responses back to the client.
|
|
* @returns {Object} - A response object containing the fetched questions or an error message.
|
|
*/
|
|
export const getAssessmentQuestions = catchAsyncAction(async (req, res) => {
|
|
try {
|
|
const questions = await getAllQuestions(); // Get all questions from DB
|
|
|
|
if (!questions || questions.length === 0) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, responseMessages.QUESTIONS_NOT_FOUND, {});
|
|
}
|
|
|
|
// Return all questions in the response
|
|
return makeResponse(res, statusCodes.SUCCESS, true, responseMessages.QUESTIONS_FETCHED, questions);
|
|
|
|
} catch (error) {
|
|
const code = error?.code || statusCodes.SERVER_ERROR;
|
|
const message = error?.message || responseMessages.SOMETHING_WRONG;
|
|
|
|
return makeResponse(res, code, false, message, {});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* API handler to add user assessment responses.
|
|
* Validates user input and saves user responses to the database.
|
|
*
|
|
* @param {Object} req - The request object containing user responses.
|
|
* @param {Object} res - The response object used to send responses back to the client.
|
|
* @returns {Object} - A response object indicating the success or failure of the operation.
|
|
*/
|
|
export const addUserAssessmentResponse = catchAsyncAction(async (req, res) => {
|
|
const { userId } = req.user; // Get userId from decoded JWT
|
|
|
|
try {
|
|
// Fetch current user details to check for changes
|
|
const currentUser = await getUserById(userId);
|
|
|
|
if (!currentUser) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, responseMessages.USER_NOT_FOUND, {});
|
|
}
|
|
|
|
// Initialize reqBody with default empty values
|
|
let reqBody = {
|
|
experience: "",
|
|
frequency: "",
|
|
struggle_area: "",
|
|
playing_style: "",
|
|
improvement_focus: "",
|
|
session_duration: ""
|
|
};
|
|
|
|
|
|
const answers = req.body.answers || []; // Extract answers from request body
|
|
answers.forEach((answer) => {
|
|
switch (answer.questionId) {
|
|
case 1:
|
|
reqBody.experience = answer.selectedOption; // Set experience based on selectedOption
|
|
break;
|
|
case 2:
|
|
reqBody.frequency = answer.selectedOption; // Set frequency based on selectedOption
|
|
break;
|
|
case 3:
|
|
reqBody.struggle_area = answer.selectedOption; // Set struggle_area based on selectedOption
|
|
break;
|
|
case 4:
|
|
reqBody.playing_style = answer.selectedOption; // Set playing_style based on selectedOption
|
|
break;
|
|
case 6:
|
|
reqBody.improvement_focus = answer.selectedOption; // Set improvement_focus based on selectedOption
|
|
break;
|
|
case 7:
|
|
reqBody.session_duration = answer.selectedOption; // Set session_duration based on selectedOption
|
|
break;
|
|
default:
|
|
break; // Ignore unrecognized question IDs
|
|
}
|
|
});
|
|
|
|
// Check if all keys in reqBody are non-empty
|
|
const missingFields = [];
|
|
for (const [key, value] of Object.entries(reqBody)) {
|
|
if (value === "" || value === null || value === undefined) {
|
|
missingFields.push(key);
|
|
}
|
|
}
|
|
|
|
if (missingFields.length > 0) {
|
|
// If there are missing fields, return an error response
|
|
return makeResponse(res, statusCodes.BAD_REQUEST, false, "Please submit all answers", {});
|
|
}
|
|
|
|
const analysisData = await getTrainingAnalysis(reqBody); // Get training analysis based on user responses
|
|
if (!analysisData) {
|
|
return makeResponse(res, statusCodes.BAD_REQUEST, false, "Something went wrong", {});
|
|
}
|
|
|
|
const trainingData = {
|
|
drills: analysisData.data.drills,
|
|
recommendation: analysisData.data.recommendation,
|
|
videos: analysisData.data.videos,
|
|
yoga_exercises: analysisData.data.yoga_exercises,
|
|
weekly_plan: analysisData.data.weekly_plan,
|
|
videos_watched: analysisData.data.videos_watched ?? [],
|
|
}
|
|
trainingData.user_id = userId;
|
|
|
|
|
|
const addFields = {
|
|
user_id: userId,
|
|
answers: JSON.stringify(answers) || ""
|
|
};
|
|
|
|
const data = await addUserAnswersByUserId(addFields); // Save user answers
|
|
const trainingDrillsData = await addUserDrillsByUserId(trainingData); // Save training data
|
|
console.log(trainingDrillsData); // Log training drills data for debugging
|
|
|
|
|
|
return makeResponse(res, statusCodes.SUCCESS, true, responseMessages.DATA_ADDED, { answersRes: data, trainingDrillsData });
|
|
|
|
} catch (error) {
|
|
const code = error?.code || statusCodes.SERVER_ERROR;
|
|
const message = error?.message || responseMessages.SOMETHING_WRONG;
|
|
|
|
return makeResponse(res, code, false, message, {});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* API handler to get user answers.
|
|
* Fetches user answers from the database and returns them.
|
|
*
|
|
* @param {Object} req - The request object.
|
|
* @param {Object} res - The response object used to send responses back to the client.
|
|
* @returns {Object} - A response object containing the fetched answers or an error message.
|
|
*/
|
|
export const getUserAnswers = catchAsyncAction(async (req, res) => {
|
|
const { userId } = req.user; // Get userId from decoded JWT
|
|
try {
|
|
// Fetch current user details to check for changes
|
|
const currentUser = await getUserById(userId);
|
|
|
|
if (!currentUser) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, responseMessages.USER_NOT_FOUND, {});
|
|
}
|
|
|
|
const data = await getUserAnswersByUserId(userId); // Get user answers
|
|
|
|
// Return the updated user data (excluding password)
|
|
return makeResponse(res, statusCodes.SUCCESS, true, responseMessages.DATA_FETCHED, data);
|
|
} catch (error) {
|
|
const code = error?.code || statusCodes.SERVER_ERROR;
|
|
const message = error?.message || responseMessages.SOMETHING_WRONG;
|
|
|
|
return makeResponse(res, code, false, message, {});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Helper function to handle AI analysis.
|
|
* Sends user data to the AI server for analysis and returns the response.
|
|
*
|
|
* @param {Object} body - The data to be sent to the AI server.
|
|
* @returns {Object|null} - The response from the AI server or null if an error occurs.
|
|
*/
|
|
const getTrainingAnalysis = async (body) => {
|
|
const postApiUrl = `${privateKey.AI_SERVER_URL}recommend`; // Construct the API URL
|
|
console.log(postApiUrl); // Log the API URL for debugging
|
|
try {
|
|
const aiResponse = await axios.post(postApiUrl, body); // Send POST request to AI server
|
|
return aiResponse;
|
|
} catch (err) {
|
|
console.error('AI analysis error:', err);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* API handler to get user training details for a specific day.
|
|
* Fetches training data from the database and filters it by day.
|
|
*
|
|
* @param {Object} req - The request object containing the day query parameter.
|
|
* @param {Object} res - The response object used to send responses back to the client.
|
|
* @returns {Object} - A response object containing the training data for the specified day or an error message.
|
|
*/
|
|
export const getUserDayTraining = catchAsyncAction(async (req, res) => {
|
|
const { userId } = req.user; // Get userId from decoded JWT
|
|
try {
|
|
const { day } = req.query; // Get day from query parameters
|
|
|
|
const currentUser = await getUserById(userId);
|
|
|
|
if (!currentUser) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, responseMessages.USER_NOT_FOUND, {});
|
|
}
|
|
|
|
const data = await getUserTrainingByUserId(userId);
|
|
if (!data) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, 'Training Details Not Found', {});
|
|
}
|
|
let dayObject = data;
|
|
if (day) {
|
|
dayObject = data?.dataValues?.weekly_plan.filter(item => item.day === `Day ${day}`)[0]; // Filter training data by day
|
|
dayObject.videos_watched = data?.dataValues?.videos_watched;
|
|
}
|
|
return makeResponse(res, statusCodes.SUCCESS, true, responseMessages.DATA_FETCHED, dayObject ?? 'No training for the day'); // Return training data or message
|
|
} catch (error) {
|
|
const code = error?.code || statusCodes.SERVER_ERROR;
|
|
const message = error?.message || responseMessages.SOMETHING_WRONG;
|
|
return makeResponse(res, code, false, message, {});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* API handler to update the list of watched videos by the user.
|
|
* Validates input and updates the training record in the database.
|
|
*
|
|
* @param {Object} req - The request object containing the day query parameter.
|
|
* @param {Object} res - The response object used to send responses back to the client.
|
|
* @returns {Object} - A response object indicating the success or failure of the operation.
|
|
*/
|
|
export const updateVideoWatchByUser = catchAsyncAction(async (req, res) => {
|
|
const { userId } = req.user; // Get userId from decoded JWT
|
|
try {
|
|
const { day } = req.query; // Get day from query parameters
|
|
// Fetch current user details to check for changes
|
|
const currentUser = await getUserById(userId);
|
|
|
|
if (!currentUser) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, responseMessages.USER_NOT_FOUND, {});
|
|
}
|
|
|
|
|
|
const training = await getUserTrainingByUserId(userId);
|
|
|
|
if (!training) {
|
|
return makeResponse(res, statusCodes.NOT_FOUND, false, 'Training Details Not Found', {});
|
|
}
|
|
|
|
// Ensure videos_watched is initialized as an empty array if it's null or undefined
|
|
if (!Array.isArray(training.videos_watched)) {
|
|
training.videos_watched = [];
|
|
}
|
|
|
|
const newVideo = day; // Set new video to be added
|
|
|
|
|
|
if (!training.videos_watched.includes(newVideo)) {
|
|
// Add the new value to the array if it doesn't exist
|
|
training.videos_watched = [...training.videos_watched, newVideo]; // Update the watched videos array
|
|
}
|
|
|
|
// Save the updated training record
|
|
const data = await training.save(); // Persist changes to the database
|
|
|
|
return makeResponse(res, statusCodes.SUCCESS, true, responseMessages.DATA_FETCHED, data);
|
|
} catch (error) {
|
|
const code = error?.code || statusCodes.SERVER_ERROR;
|
|
const message = error?.message || responseMessages.SOMETHING_WRONG;
|
|
return makeResponse(res, code, false, message, {});
|
|
}
|
|
});
|