From 7d8ed6d0ee5837571ff47e58a8d22fa4958ad976 Mon Sep 17 00:00:00 2001 From: Ayobami Date: Tue, 15 Jul 2025 17:41:52 +0100 Subject: [PATCH] feat: complete day 8 --- day8/models/index.js | 82 ++++--- day8/models/question.js | 34 +++ day8/models/quiz.js | 25 +++ day8/package.json | 3 +- day8/quiz.html | 482 +++++++++++++++++++--------------------- day8/routes/index.js | 35 ++- day8/seed.js | 39 ++++ 7 files changed, 407 insertions(+), 293 deletions(-) create mode 100644 day8/models/question.js create mode 100644 day8/models/quiz.js create mode 100644 day8/seed.js diff --git a/day8/models/index.js b/day8/models/index.js index 8c44682..a19a591 100644 --- a/day8/models/index.js +++ b/day8/models/index.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; /*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/ /** * Sequelize File @@ -8,49 +8,63 @@ * @author Ryan Wong * */ -const fs = require('fs'); -const path = require('path'); -let Sequelize = require('sequelize'); +const fs = require("fs"); +const path = require("path"); +let Sequelize = require("sequelize"); const basename = path.basename(__filename); -const { DataTypes } = require('sequelize'); +const { DataTypes } = require("sequelize"); const config = { - DB_DATABASE: 'mysql', - DB_USERNAME: 'root', - DB_PASSWORD: 'root', - DB_ADAPTER: 'mysql', - DB_NAME: 'day_1', - DB_HOSTNAME: 'localhost', + DB_DATABASE: "mysql", + DB_USERNAME: "root", + DB_PASSWORD: process.env.DB_PASSWORD || "root", + DB_ADAPTER: "mysql", + DB_NAME: "day_8", + DB_HOSTNAME: "localhost", DB_PORT: 3306, }; let db = {}; -let sequelize = new Sequelize(config.DB_DATABASE, config.DB_USERNAME, config.DB_PASSWORD, { - dialect: config.DB_ADAPTER, - username: config.DB_USERNAME, - password: config.DB_PASSWORD, - database: config.DB_NAME, - host: config.DB_HOSTNAME, - port: config.DB_PORT, - logging: console.log, - timezone: '-04:00', - pool: { - maxConnections: 1, - minConnections: 0, - maxIdleTime: 100, - }, - define: { - timestamps: false, - underscoredAll: true, - underscored: true, - }, -}); +let sequelize = new Sequelize( + config.DB_NAME, + config.DB_USERNAME, + config.DB_PASSWORD, + { + dialect: config.DB_ADAPTER, + username: config.DB_USERNAME, + password: config.DB_PASSWORD, + database: config.DB_NAME, + host: config.DB_HOSTNAME, + port: config.DB_PORT, + logging: console.log, + timezone: "-04:00", + pool: { + maxConnections: 1, + minConnections: 0, + maxIdleTime: 100, + }, + define: { + timestamps: false, + underscoredAll: true, + underscored: true, + }, + } +); -// sequelize.sync({ force: true }); +sequelize + .sync() + .then(() => { + console.log("All tables synced successfully."); + }) + .catch((err) => { + console.error("Failed to sync tables:", err); + }); fs.readdirSync(__dirname) .filter((file) => { - return file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js'; + return ( + file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js" + ); }) .forEach((file) => { var model = require(path.join(__dirname, file))(sequelize, DataTypes); @@ -66,4 +80,4 @@ Object.keys(db).forEach((modelName) => { db.sequelize = sequelize; db.Sequelize = Sequelize; -module.exports = db; \ No newline at end of file +module.exports = db; diff --git a/day8/models/question.js b/day8/models/question.js new file mode 100644 index 0000000..33deca6 --- /dev/null +++ b/day8/models/question.js @@ -0,0 +1,34 @@ +module.exports = (sequelize, DataTypes) => { + const Question = sequelize.define( + "question", + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + }, + quizId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: "quiz", + key: "id", + }, + }, + questionText: DataTypes.STRING, + options: DataTypes.JSON, + answer: DataTypes.STRING, + }, + { + timestamps: true, + freezeTableName: true, + tableName: "question", + } + ); + + Question.associate = (models) => { + Question.belongsTo(models.quiz, { foreignKey: "quizId", as: "quiz" }); + }; + + return Question; +}; diff --git a/day8/models/quiz.js b/day8/models/quiz.js new file mode 100644 index 0000000..9da9a17 --- /dev/null +++ b/day8/models/quiz.js @@ -0,0 +1,25 @@ +module.exports = (sequelize, DataTypes) => { + const Quiz = sequelize.define( + "quiz", + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + }, + title: DataTypes.STRING, + description: DataTypes.STRING, + }, + { + timestamps: true, + freezeTableName: true, + tableName: "quiz", + } + ); + + Quiz.associate = (models) => { + Quiz.hasMany(models.question, { foreignKey: "quizId", as: "questions" }); + }; + + return Quiz; +}; diff --git a/day8/package.json b/day8/package.json index 219c20e..cd71cf0 100644 --- a/day8/package.json +++ b/day8/package.json @@ -3,7 +3,8 @@ "version": "0.0.0", "private": true, "scripts": { - "start": "node ./bin/www" + "start": "node ./bin/www", + "dev": "node --watch --env-file=.env ./bin/www" }, "dependencies": { "cookie-parser": "~1.4.4", diff --git a/day8/quiz.html b/day8/quiz.html index 0711b0e..5c52f3d 100644 --- a/day8/quiz.html +++ b/day8/quiz.html @@ -1,277 +1,249 @@ - - - - - - + + + + + Quiz - - - -
- - -

Quiz

- -
- -

-
- - -
- -
-
+ + +
+

Quiz

+ +
+

+
    + + +
    + +
    +
    - - \ No newline at end of file + + diff --git a/day8/routes/index.js b/day8/routes/index.js index ecca96a..24f8599 100644 --- a/day8/routes/index.js +++ b/day8/routes/index.js @@ -1,9 +1,38 @@ -var express = require('express'); +var express = require("express"); var router = express.Router(); +const db = require("../models"); +const path = require("path"); /* GET home page. */ -router.get('/', function(req, res, next) { - res.render('index', { title: 'Express' }); +router.get("/", function (req, res, next) { + res.render("index", { title: "Express" }); +}); + +// API endpoint to get quiz and questions +router.get("/api/quiz", async function (req, res) { + try { + const quiz = await db.quiz.findOne({ + include: [{ model: db.question, as: "questions" }], + }); + if (!quiz) { + return res.json({ success: false, error: "Quiz not found" }); + } + // Parse options from JSON string to array for each question + const quizData = quiz.toJSON(); + quizData.questions = quizData.questions.map((q) => ({ + ...q, + options: + typeof q.options === "string" ? JSON.parse(q.options) : q.options, + })); + res.json({ success: true, data: quizData }); + } catch (err) { + res.json({ success: false, error: err.message }); + } +}); + +// Serve quiz.html at /quiz +router.get("/quiz", function (req, res) { + res.sendFile(path.join(__dirname, "../quiz.html")); }); module.exports = router; diff --git a/day8/seed.js b/day8/seed.js new file mode 100644 index 0000000..a89cddc --- /dev/null +++ b/day8/seed.js @@ -0,0 +1,39 @@ +const db = require("./models/index"); + +async function seed() { + await db.sequelize.sync({ force: true }); + + const quiz = await db.quiz.create({ + title: "JavaScript Basics", + description: "A quiz on JavaScript fundamentals.", + }); + + await db.question.bulkCreate([ + { + quizId: quiz.id, + questionText: 'What is the output of 1 + "2" in JavaScript?', + options: JSON.stringify(["3", "12", "NaN", "Error"]), + answer: "12", + }, + { + quizId: quiz.id, + questionText: "Which company developed JavaScript?", + options: JSON.stringify(["Netscape", "Microsoft", "Google", "Apple"]), + answer: "Netscape", + }, + { + quizId: quiz.id, + questionText: "What keyword declares a variable in JavaScript?", + options: JSON.stringify(["var", "let", "const", "All of the above"]), + answer: "All of the above", + }, + ]); + + console.log("Database seeded!"); + process.exit(); +} + +seed().catch((err) => { + console.error(err); + process.exit(1); +});