Commit 5e48299a by Shaganaz

Implemented ORM and added gitignore

parent 1a2c8ee7
node_modules/
.env
\ No newline at end of file
......@@ -16,8 +16,8 @@ headers {
body:json {
{
"email":"admin@gmail.com",
"password":"admin@123",
"role":"admin"
"email":"shaganaz@gmail.com",
"password":"shaganaz",
"role":"user"
}
}
......@@ -15,13 +15,12 @@ headers {
}
auth:bearer {
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImVtYWlsIjoiYWRtaW5AZ21haWwuY29tIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzQ4NTIyMTg2LCJleHAiOjE3NDg1MjU3ODZ9.WTUXrCWQuLqncxQzt9XB2HBMvJ5OXb2MeYP6SWmHUAc
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsImVtYWlsIjoiYWRtaW5AZ21haWwuY29tIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzQ4OTUzNDIxLCJleHAiOjE3NDg5NTcwMjF9.jc1Y0rh69qKpFe-fkYHnLYnukO7nAkCiTRjFUxYsiFE
}
body:json {
{
"user_id": 2,
"quiz_id": 5
"user_id": 1,
"quiz_id": 3
}
}
......@@ -5,11 +5,11 @@ meta {
}
get {
url: http://localhost:3000/api/dashboard/user
url: http://localhost:3000/api/dashboard/admin
body: none
auth: inherit
auth: bearer
}
headers {
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsImVtYWlsIjoic2hhZ2FuYXpAZ21haWwuY29tIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3NDg1MTQzNjEsImV4cCI6MTc0ODUxNzk2MX0.BOFvb33tIZYkXTJ_1yG8xNfhdKojjVvNVgNRqp9lvw0
auth:bearer {
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIsImVtYWlsIjoiYWRtaW5AZ21haWwuY29tIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNzQ4OTQ5NTE3LCJleHAiOjE3NDg5NTMxMTd9.Er7pbtCX6r9aSzClFEl0a7ptWN0OVxYB--OfdRKLXO8
}
......@@ -16,9 +16,9 @@ headers {
body:json {
{
"email": "shaganaz@gmail.com",
"password": "shaganaz",
"role": "user"
"email": "admin@gmail.com",
"password": "admin@123",
"role": "admin"
}
......
......@@ -5,7 +5,15 @@ meta {
}
get {
url: http://localhost:3000/api/user/take-quiz/2/1
body: none
auth: inherit
url: /api/user/take-quiz/3/1
body: json
auth: bearer
}
headers {
content-type: application/json
}
auth:bearer {
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImVtYWlsIjoic2hhZ2FuYXpAZ21haWwuY29tIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3NDg5NTQzMDAsImV4cCI6MTc0ODk1NzkwMH0.9GOhjHWK7ugeiWGTiElWFpdGYS0GdnB9mTkZSkNc7Ok
}
const express = require('express');
require('dotenv').config();
require('./server/config/database');
const db= require('./models')
const app = express();
......
require('dotenv').config();
module.exports = {
development: {
username: process.env.DB_USER || 'root',
password: process.env.DB_PASS || '',
database: process.env.DB_NAME || 'QuizNode',
host: process.env.DB_HOST || '127.0.0.1',
dialect: 'mysql'
}
};
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
role: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Users');
}
};
\ No newline at end of file
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('quizzes', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
title: {
type: Sequelize.STRING,
allowNull:false
},
description:{
type:Sequelize.STRING,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('quizzes');
}
};
\ No newline at end of file
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('questions', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
quiz_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'quizzes',
key:'id'
},
onDelete:'cascade'
},
question_text:{
type:Sequelize.STRING,
allowNull:false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('questions');
}
};
\ No newline at end of file
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('options', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
question_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'questions',
key:'id'
},
onDelete:'cascade'
},
option_text:{
type:Sequelize.STRING,
allowNull:false
},
is_correct:{
type:Sequelize.BOOLEAN,
allowNull:false,
defaultValue:false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('options');
}
};
\ No newline at end of file
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('user_quizzes', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
user_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'users',
key:'id'
},
onDelete:'cascade'
},
quiz_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'quizzes',
key:'id'
},
onDelete:'cascade'
},
status:{
type:Sequelize.STRING,
allowNull:false,
defaultValue:'pending'
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('user_quizzes');
}
};
\ No newline at end of file
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('user_answers', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
user_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'users',
key:'id'
},
onDelete:'cascade'
},
quiz_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'quizzes',
key:'id'
},
onDelete:'cascade'
},
question_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'questions',
key:'id'
},
onDelete:'cascade'
},
answer:{
type:Sequelize.INTEGER,
allowNull:false
},
is_correct:{
type:Sequelize.BOOLEAN,
allowNull:false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('user_answers');
}
};
\ No newline at end of file
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('results', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
user_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'users',
key:'id'
},
onDelete:'cascade'
},
quiz_id: {
type: Sequelize.INTEGER,
allowNull:false,
references:{
model:'quizzes',
key:'id'
},
onDelete:'cascade'
},
score:{
type:Sequelize.INTEGER,
allowNull:false
},
total:{
type:Sequelize.INTEGER,
allowNull:false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('results');
}
};
\ No newline at end of file
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const process = require('process');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.js')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (
file.indexOf('.') !== 0 &&
file !== basename &&
file.slice(-3) === '.js' &&
file.indexOf('.test.js') === -1
);
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class option extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
option.belongsTo(models.question,{
foreignKey:'question_id',
onDelete:'cascade'
});
}
}
option.init({
option_text:{
type:DataTypes.STRING,
allowNull:false
},
question_id:{
type:DataTypes.INTEGER,
allowNull:false
},
is_correct:{
type:DataTypes.BOOLEAN,
allowNull:false,
defaultValue:false
}
}, {
sequelize,
modelName: 'option',
tableName:'options',
timestamps:true
});
return option;
};
\ No newline at end of file
'use strict';
const {
Model,
INTEGER
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class question extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
question.belongsTo(models.quiz,{
foreignKey:'quiz_id',
onDelete:'cascade'
})
}
}
question.init({
quiz_id: {
type:DataTypes.INTEGER,
allowNull:false
},
question_text: {
type:DataTypes.STRING,
allowNull:false
}
}, {
sequelize,
modelName: 'question',
tableName:'questions',
timestamps:true
});
return question;
};
\ No newline at end of file
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class quiz extends Model {
static associate(models) {
}
}
quiz.init({
title: DataTypes.STRING,
description: DataTypes.STRING
}, {
sequelize,
modelName: 'quiz',
tableName: 'quizzes',
timestamps: true
});
return quiz;
};
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class result extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
result.belongsTo(models.user,{
foreignKey:'user_id',
onDelete:'cascade'
});
result.belongsTo(models.quiz,{
foreignKey:'quiz_id',
onDelete:'cascade'
});
}
}
result.init({
user_id:{
type:DataTypes.INTEGER,
allowNull:false
},
quiz_id:{
type:DataTypes.INTEGER,
allowNull:false
},
score:{
type:DataTypes.INTEGER,
allowNull:false,
},
total:{
type:DataTypes.INTEGER,
allowNull:false,
}
}, {
sequelize,
modelName: 'result',
tableName:'results'
});
return result;
};
\ No newline at end of file
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class user extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
}
user.init({
email: DataTypes.STRING,
password: DataTypes.STRING,
role: DataTypes.STRING
}, {
sequelize,
modelName: 'user',
tableName:'Users'
});
return user;
};
\ No newline at end of file
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class user_answers extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
user_answers.belongsTo(models.user,{
foreignKey:'user_id',
onDelete:'cascade'
});
user_answers.belongsTo(models.quiz,{
foreignKey:'quiz_id',
onDelete:'cascade'
});
user_answers.belongsTo(models.question,{
foreignKey:'question_id',
onDelete:'cascade'
});
user_answers.belongsTo(models.option, {
foreignKey: 'answer',
as: 'selectedOption',
onDelete: 'cascade',
});
}
}
user_answers.init({
user_id:{
type:DataTypes.INTEGER,
allowNull:false
},
quiz_id:{
type:DataTypes.INTEGER,
allowNull:false
},
question_id:{
type:DataTypes.INTEGER,
allowNull:false
},
answer:{
type:DataTypes.INTEGER,
allowNull:false
},
is_correct:{
type:DataTypes.BOOLEAN,
allowNull:false,
defaultValue:false
}
}, {
sequelize,
modelName: 'user_answers',
tableName:'user_answers'
});
return user_answers;
};
\ No newline at end of file
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class user_quizzes extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
user_quizzes.belongsTo(models.user,{
foreignKey:'user_id',
onDelete:'cascade'
});
user_quizzes.belongsTo(models.quiz,{
foreignKey:'quiz_id',
onDelete:'cascade'
});
}
}
user_quizzes.init({
user_id:{
type:DataTypes.INTEGER,
allowNull:false
},
quiz_id:{
type:DataTypes.INTEGER,
allowNull:false
},
status:{
type:DataTypes.STRING,
allowNull:false,
defaultValue:'pending'
}
}, {
sequelize,
modelName: 'user_quizzes',
tableName:'user_quizzes'
});
return user_quizzes;
};
\ No newline at end of file
......@@ -18,6 +18,7 @@
"jsonwebtoken": "^9.0.2",
"mysql2": "^3.14.1",
"nodemon": "^3.1.10",
"sequelize": "^6.37.7"
"sequelize": "^6.37.7",
"sequelize-cli": "^6.6.3"
}
}
const mysql = require('mysql2/promise');
require('dotenv').config();
const conn = mysql.createPool({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASS || '',
database: process.env.DB_NAME || 'QuizNode',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
module.exports = conn;
const db=require('../config/database');
exports.createQuiz=async(req,res)=>{
const {title,description} = req.body;
try{
await db.query('insert into quizzes(title,description) values(?,?)', [title,description]);
return res.json({message:'Quiz created successfully'});
}
catch(err){
return res.json({message:'Unable to create quiz', error: err.message });
}
}
exports.createQuestion = async (req, res) => {
const { quiz_id, question_text,options,correct_answer } = req.body;
try {
const[result]=await db.query('insert into questions (quiz_id, question_text) values (?, ?)', [quiz_id, question_text]);
const questionId = result.insertId;
for (const opt of options) {
const isCorrect = opt === correct_answer ? 1 : 0;
await db.query('insert into options (question_id, option_text, is_correct) values (?, ?, ?)',[questionId, opt, isCorrect]);
}
return res.json({ message: 'Question and options created successfully' });
} catch (err) {
return res.json({ message: 'Unable to create question', error: err.message });
}
};
exports.assignQuiz = async (req, res) => {
const { user_id, quiz_id } = req.body;
try {
await db.query('insert into user_quizzes (user_id, quiz_id, status) values (?, ?, ?)',[user_id, quiz_id, 'pending']);
return res.json({ message: 'Quiz assigned to user successfully' });
} catch (err) {
return res.json({ message: 'Unable to assign quiz', error: err.message });
}
};
exports.getUserResult = async (req, res) => {
const { user_id, quiz_id } = req.params;
try {
const [results] = await db.query(`select q.question_text,
ua.answer as selected_option_id,
o1.option_text as selected_answer,
o2.option_text as correct_answer,
ua.is_correct
from user_answers ua
join questions q ON ua.question_id = q.id
join options o1 ON ua.answer = o1.id
join options o2 ON o2.question_id = q.id and o2.is_correct = 1
where ua.user_id = ? and ua.quiz_id = ?`,
[user_id, quiz_id]
);
const [summary] = await db.query(`SELECT score, total from results where user_id = ? and quiz_id = ?`,[user_id, quiz_id]);
return res.json({
score: summary[0]?.score || 0,
total: summary[0]?.total || 0,
answers: results
});
} catch (err) {
return res.status(500).json({ message: 'Error fetching user result', error: err.message });
}
};
const db = require('../../models');
exports.createQuiz=async(req,res)=>{
const {title,description} = req.body;
try{
await db.quiz.create({title,description});
return res.json({message:'Quiz created successfully'});
}
catch(err){
return res.json({message:'Unable to create quiz', error: err.message });
}
};
exports.createQuestion = async (req, res) => {
const { quiz_id, question_text,options,correct_answer } = req.body;
try {
const question=await db.question.create({quiz_id,question_text});
const option=options.map((opt)=>({
question_id:question.id,
option_text:opt,
is_correct:opt===correct_answer,
}));
await db.option.bulkCreate(option);
return res.json({ message: 'Question and options created successfully' });
} catch (err) {
return res.json({ message: 'Unable to create question', error: err.message });
}
};
exports.assignQuiz = async (req, res) => {
const { user_id, quiz_id } = req.body;
try {
await db.user_quizzes.create({user_id, quiz_id, status:'pending'});
return res.json({ message: 'Quiz assigned to user successfully' });
} catch (err) {
return res.json({ message: 'Unable to assign quiz', error: err.message });
}
};
exports.getUserResult = async (req, res) => {
const { user_id, quiz_id } = req.params;
try {
const answers = await db.user_answer.findAll({
where: { user_id, quiz_id },
include: [
{
model: db.question,
attributes: ['question_text'],
include: [
{
model: db.option,
as: 'correctOption',
where: { is_correct: true },
required: false,
attributes: ['option_text'],
},
],
},
{
model: db.option,
as: 'selectedOption',
foreignKey: 'answer',
attributes: ['option_text'],
},
],
});
const summary = await db.result.findOne({
where: { user_id, quiz_id },
});
return res.json({
score: summary?.score || 0,
total: summary?.total || 0,
answers,
});
} catch (err) {
return res.status(500).json({ message: 'Error fetching user result', error: err.message });
}
};
const jwt = require('jsonwebtoken');
const db = require('../../models');
exports.register = async (req, res) => {
const { email, password, role = 'user' } = req.body;
try {
const existing = await db.user.findOne({ where: { email } });
if (existing) {
return res.json({ message: 'User already registered' });
}
await db.user.create({ email, password, role });
res.json({ message: 'User registered successfully' });
} catch (err) {
res.json({ message: 'Registration failed', error: err.message });
}
};
exports.login = async (req, res) => {
const { email, password } = req.body;
try {
const user = await db.user.findOne({ where: { email, password } });
if (!user) {
return res.json({ message: 'Invalid credentials' });
}
const token = jwt.sign(
{ userId: user.id, email: user.email, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN }
);
res.json({
message: 'Login successful',
token,
role: user.role
});
} catch (err) {
res.status(500).json({ message: 'Login failed', error: err.message });
}
};
const db=require('../config/database');
const db = require('../../models');
exports.takeQuiz=async(req,res)=>{
const {quiz_id,user_id}=req.params;
try{
const[assigned]=await db.query(`SELECT* from user_quizzes where user_id=? and quiz_id=? and status='pending'`,[user_id,quiz_id]);
if(assigned.length===0){
const assigned =await db.user_quizzes.findOne({where:{user_id,quiz_id,status:'pending'}});
if(!assigned){
return res.json({message:'Quiz completed or not assigned properly'});
}
const[quiz]=await db.query(`select id,title,description from quizzes where id=?`,[quiz_id]);
const[questions]=await db.query(`select q.id as question_id, q.question_text,
o.id as option_id, o.option_text
from questions q
join options o on q.id=o.question_id
where q.quiz_id=?
order by q.id,o.id`,[quiz_id]);
const questionsMap = {};
for (const row of questions) {
if (!questionsMap[row.question_id]) {
questionsMap[row.question_id] = {
question_id: row.question_id,
question_text: row.question_text,
options: []
};
}
questionsMap[row.question_id].options.push({
option_id: row.option_id,
option_text: row.option_text
});
const quiz=await db.quiz.findByPk(quiz_id,{
attributes:['id','title','description'],
include:{
model:db.question,
attributes:['id','question_text'],
include:{
model:db.option,
attributes:['id','option_text']
}
},
order:[
[db.question,'id','ASC'],
[db.question,db.option,'id','ASC']
]
});
if(!quiz){
return res.json({message:'Quiz not found'});
}
return res.json({
quiz: quiz[0],
questions: Object.values(questionsMap)
});
return res.json({quiz});
}
catch(err){
return res.json({message:"Error fetching quiz",error:err.message});
......@@ -44,27 +38,13 @@ exports.submitQuiz = async (req, res) => {
let score = 0;
const total = answers.length;
for (const ans of answers) {
const [correct] = await db.query(
'select is_correct from options where id = ?',
[ans.selected_option_id]
);
const correct= await db.option.findOne({where:{id:ans.selected_option_id}});
const isCorrect = correct[0]?.is_correct === 1 ? 1 : 0;
if (isCorrect) score++;
await db.query(
`insert into user_answers (user_id, quiz_id, question_id, answer, is_correct)
values (?, ?, ?, ?, ?)`,
[user_id, quiz_id, ans.question_id, ans.selected_option_id, isCorrect]
);
await db.user_answer.create({user_id, quiz_id, question_id:ans.question_id, answer:ans.selected_option_id, is_correct:isCorrect});
}
await db.query(
`insert into results (user_id, quiz_id, score, total)
values (?, ?, ?, ?)`,
[user_id, quiz_id, score, total]
);
await db.query(
`update user_quizzes set status = 'completed' where user_id = ? AND quiz_id = ?`,
[user_id, quiz_id]
);
await db.results.create({user_id, quiz_id, score, total});
await db.user_quizzes.update({status:'completed'},{where:{user_id,quiz_id}});
return res.json({ message: 'Quiz submitted', score, total });
} catch (err) {
return res.status(500).json({ message: 'Error submitting quiz', error: err.message });
......
const express=require('express');
const router=express.Router();
const authenticateAdmin=require('../middleware/authmiddleware');
const adminctrl=require('../controller/adminController');
const adminctrl=require('../controller/adminController.js');
router.post('/create-quiz',authenticateAdmin,adminctrl.createQuiz);
router.post('/create-question',authenticateAdmin,adminctrl.createQuestion);
......
const express = require('express');
const jwt=require('jsonwebtoken');
const router = express.Router();
const db=require('../config/database');
const authController = require('../controller/authController');
router.post('/register', async (req, res) => {
const { email, password, role = 'user' } = req.body;
router.post('/register', authController.register);
router.post('/login', authController.login);
const [existing] = await db.query('SELECT * FROM users WHERE email = ?', [email]);
if (existing.length > 0) {
return res.status(409).json({ message: 'User already registered' });
}
await db.query('INSERT INTO users (email, password, role) VALUES (?, ?, ?)', [email, password, role]);
res.status(201).json({ message: 'User registered successfully' });
});
router.post('/login', async (req, res) => {
const { email, password } = req.body;
const [rows] = await db.query('SELECT * FROM users WHERE email = ? AND password = ?', [email, password]);
if (rows.length === 0) {
return res.status(401).json({ message: 'Invalid credentials' });
}
const user = rows[0];
const token = jwt.sign(
{ userId: user.id, email: user.email, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN }
);
const dashboardPath=user.role==='admin' ? 'api/dashhboard/admin' : 'api/dashboard/user';
res.json({
message: 'Login successful',
token,
role: user.role
});
});
module.exports = router;
\ No newline at end of file
module.exports = router;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment