diff --git a/.gitignore b/.gitignore index 30bc162..7af7f04 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/node_modules \ No newline at end of file +/node_modules +.env \ No newline at end of file diff --git a/config/config.json b/config/config.js similarity index 83% rename from config/config.json rename to config/config.js index 3b13a9b..f60ad32 100644 --- a/config/config.json +++ b/config/config.js @@ -1,6 +1,8 @@ -{ +require("dotenv").config() + +module.exports = { "development": { - "url": "YOUR_ELEPHANTSQL_URL_HERE", + "url": process.env.DATABASE_URL_DEV, "dialect": "postgres", "operatorsAliases": "0" }, diff --git a/config/constants.js b/config/constants.js index 6e2cdc3..ce3b931 100644 --- a/config/constants.js +++ b/config/constants.js @@ -1,4 +1,4 @@ module.exports = { SALT_ROUNDS: 10, - PORT: process.env.PORT || 4000 + PORT: process.env.PORT || 4000, }; diff --git a/index.js b/index.js index 6de13ea..2249b7d 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,13 @@ +require("dotenv").config() + const express = require("express"); const loggerMiddleWare = require("morgan"); const corsMiddleWare = require("cors"); const { PORT } = require("./config/constants"); const authRouter = require("./routers/auth"); const authMiddleWare = require("./auth/middleware"); +const exercises = require("./routers/exercisesRouter") +const profile = require("./routers/ProfileRouter") const app = express(); @@ -113,11 +117,8 @@ if (process.env.DELAY) { * */ -/** - * Routes - * - * Define your routes here (now that middlewares are configured) - */ +app.use("/exercises", exercises) +app.use("/profile", profile) // GET endpoint for testing purposes, can be removed app.get("/", (req, res) => { diff --git a/migrations/20200318210344-create-user.js b/migrations/0-create-user.js similarity index 74% rename from migrations/20200318210344-create-user.js rename to migrations/0-create-user.js index 8705f70..a85e7bb 100644 --- a/migrations/20200318210344-create-user.js +++ b/migrations/0-create-user.js @@ -8,7 +8,11 @@ module.exports = { primaryKey: true, type: Sequelize.INTEGER, }, - name: { + fullName: { + type: Sequelize.STRING, + allowNull: false, + }, + image : { type: Sequelize.STRING, allowNull: false, }, @@ -21,6 +25,14 @@ module.exports = { type: Sequelize.STRING, allowNull: false, }, + ranking: { + type: Sequelize.STRING, + allowNull: false, + }, + totalExp: { + type: Sequelize.INTEGER, + allowNull: false, + }, createdAt: { allowNull: false, type: Sequelize.DATE, diff --git a/migrations/1-create-exercise.js b/migrations/1-create-exercise.js new file mode 100644 index 0000000..d0eb280 --- /dev/null +++ b/migrations/1-create-exercise.js @@ -0,0 +1,32 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('exercises', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING, + allowNull: false, + }, + content: { + type: Sequelize.TEXT, + allowNull: false, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('exercises'); + } +}; \ No newline at end of file diff --git a/migrations/2-create-completed-exercise.js b/migrations/2-create-completed-exercise.js new file mode 100644 index 0000000..b837f73 --- /dev/null +++ b/migrations/2-create-completed-exercise.js @@ -0,0 +1,52 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('completedExercises', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "users", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + exerciseId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "exercises", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + timeTaken: { + type: Sequelize.TIME, + allowNull: false, + }, + exp: { + type: Sequelize.INTEGER, + allowNull: false, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('completedExercises'); + } +}; \ No newline at end of file diff --git a/migrations/3-create-quiz-question.js b/migrations/3-create-quiz-question.js new file mode 100644 index 0000000..8d06f75 --- /dev/null +++ b/migrations/3-create-quiz-question.js @@ -0,0 +1,54 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('quizQuestions', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + question: { + type: Sequelize.TEXT, + allowNull: false, + }, + answer: { + type: Sequelize.TEXT, + allowNull: false, + }, + incorrect1: { + type: Sequelize.TEXT, + allowNull: false, + }, + incorrect2: { + type: Sequelize.TEXT, + allowNull: false, + }, + incorrect3: { + type: Sequelize.TEXT, + allowNull: false, + }, + exerciseId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "exercises", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "SET NULL", + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('quizQuestions'); + } +}; \ No newline at end of file diff --git a/migrations/4-create-completed-quiz.js b/migrations/4-create-completed-quiz.js new file mode 100644 index 0000000..fcbe565 --- /dev/null +++ b/migrations/4-create-completed-quiz.js @@ -0,0 +1,48 @@ +'use strict'; +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.createTable('completedQuizzes', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "users", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + quizQuestionId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "quizQuestions", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + exp: { + type: Sequelize.INTEGER, + allowNull: false, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('completedQuizzes'); + } +}; \ No newline at end of file diff --git a/models/completedexercise.js b/models/completedexercise.js new file mode 100644 index 0000000..1aa67e2 --- /dev/null +++ b/models/completedexercise.js @@ -0,0 +1,50 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class completedExercise 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 + } + }; + completedExercise.init({ + userId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: "users", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + exerciseId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: "exercises", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + timeTaken: { + type: DataTypes.TIME, + allowNull: false, + }, + exp: { + type: DataTypes.INTEGER, + allowNull: false, + } + }, { + sequelize, + modelName: 'completedExercise', + }); + return completedExercise; +}; \ No newline at end of file diff --git a/models/completedquiz.js b/models/completedquiz.js new file mode 100644 index 0000000..c695ac8 --- /dev/null +++ b/models/completedquiz.js @@ -0,0 +1,46 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class completedQuiz 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 + } + }; + completedQuiz.init({ + userId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: "users", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + quizQuestionId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: "quizQuestions", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "CASCADE", + }, + exp: { + type: DataTypes.INTEGER, + allowNull: false, + } + }, { + sequelize, + modelName: 'completedQuiz', + }); + return completedQuiz; +}; \ No newline at end of file diff --git a/models/exercise.js b/models/exercise.js new file mode 100644 index 0000000..f343e97 --- /dev/null +++ b/models/exercise.js @@ -0,0 +1,34 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class exercise 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) { + exercise.hasMany(models.quizQuestion) + exercise.belongsToMany(models.user, { + through: "completedExercises", + key: "exerciseId", + }) + } + }; + exercise.init({ + name: { + type: DataTypes.STRING, + allowNull: false, + }, + content: { + type: DataTypes.TEXT, + allowNull: false, + } + }, { + sequelize, + modelName: 'exercise', + }); + return exercise; +}; \ No newline at end of file diff --git a/models/index.js b/models/index.js index 266d5a7..3b7d6f9 100644 --- a/models/index.js +++ b/models/index.js @@ -5,7 +5,7 @@ const path = require("path"); const Sequelize = require("sequelize"); const basename = path.basename(__filename); const env = process.env.NODE_ENV || "development"; -const config = require(__dirname + "/../config/config.json")[env]; +const config = require(__dirname + "/../config/config.js")[env]; const db = {}; let sequelize; diff --git a/models/quizquestion.js b/models/quizquestion.js new file mode 100644 index 0000000..dcd313b --- /dev/null +++ b/models/quizquestion.js @@ -0,0 +1,55 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class quizQuestion 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) { + quizQuestion.belongsToMany(models.user, { + through: "completedQuizzes", + key: "quizQuestionId", + }) + } + }; + quizQuestion.init({ + question: { + type: DataTypes.TEXT, + allowNull: false, + }, + answer: { + type: DataTypes.TEXT, + allowNull: false, + }, + incorrect1: { + type: DataTypes.TEXT, + allowNull: false, + }, + incorrect2: { + type: DataTypes.TEXT, + allowNull: false, + }, + incorrect3: { + type: DataTypes.TEXT, + allowNull: false, + }, + exerciseId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: "exercises", + key: "id", + }, + onUpdate: "CASCADE", + onDelete: "SET NULL", + } + }, { + sequelize, + modelName: 'quizQuestion', + }); + return quizQuestion; +}; \ No newline at end of file diff --git a/models/user.js b/models/user.js index d1b2dff..2c0afac 100644 --- a/models/user.js +++ b/models/user.js @@ -9,12 +9,23 @@ module.exports = (sequelize, DataTypes) => { * The `models/index` file will call this method automatically. */ static associate(models) { - // define association here + user.belongsToMany(models.exercise, { + through: "completedExercises", + key: "userId", + }) + user.belongsToMany(models.quizQuestion, { + through: "completedQuizzes", + key: "userId", + }) } } user.init( { - name: { + fullName: { + type: DataTypes.STRING, + allowNull: false, + }, + image: { type: DataTypes.STRING, allowNull: false, }, @@ -27,6 +38,14 @@ module.exports = (sequelize, DataTypes) => { type: DataTypes.STRING, allowNull: false, }, + ranking: { + type: DataTypes.STRING, + allowNull: false, + }, + totalExp: { + type: DataTypes.INTEGER, + allowNull: false, + } }, { sequelize, diff --git a/package-lock.json b/package-lock.json index 91d797e..d9a0a8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -625,6 +625,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, "dottie": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", diff --git a/package.json b/package.json index 5f88bc6..3356334 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "bcrypt": "^5.0.0", "cors": "^2.8.5", + "dotenv": "^8.2.0", "express": "^4.17.1", "jsonwebtoken": "^8.5.1", "morgan": "^1.9.1", diff --git a/routers/ProfileRouter.js b/routers/ProfileRouter.js new file mode 100644 index 0000000..cec10e7 --- /dev/null +++ b/routers/ProfileRouter.js @@ -0,0 +1,102 @@ +const { Router } = require("express") +const authMiddleware = require("../auth/middleware") + +const User = require("../models").user +const Exercises = require("../models").exercise +const CompletedExercises = require("../models").completedExercise + +const router = new Router() + +router.patch( + "/user", + authMiddleware, + async(req, res, next) => { + const userIdNeeded = req.user.id + console.log("user id test:", userIdNeeded) + if(!userIdNeeded){ + res.status(401).send("Sorry but you're not suppose to be here, please login/sign-up to continue.") + } + + const { fullName, image, email } = req.body + console.log(` + full name: ${fullName} + image: ${image} + email: ${email}`) + if(!fullName || !image || !email){ + res.status(400).send("Please enter all valid credentails") + } + + try{ + const updateUser = await User.update({ + fullName, + image, + email, + },{ + where: { + id: userIdNeeded + } + }) + if(!updateUser){ + res.status(404).send("You're information couldnt be updated, refresh and try again.") + } + + const sendUser = await User.findByPk(userIdNeeded,{ + include: [Exercises] + }) + if(!sendUser){ + res.status(404).send("Oops, you seem to be lost, try log back in and try again.") + } else { + delete sendUser.dataValues["password"] + res.status(202).send({...sendUser.dataValues}) + } + + } catch(error){ + next(error) + } + } +) + +router.get( + "/completedExercises", + authMiddleware, + async(req, res, next) => { + const userIdNeeded = req.user.id + console.log("user id test:", userIdNeeded) + if(!userIdNeeded){ + res.status(401).send("Sorry but you're not suppose to be here, please login/sign-up to continue.") + } + + try{ + const userInfo = await User.findByPk(userIdNeeded, { + include: [Exercises] + }) + // console.log("user info test", userInfo) + if(!userInfo){ + res.status(404).send("It seems you are lost, Login to be found.") + } + delete userInfo.dataValues["password"] + + const completed = await CompletedExercises.findAll({ + where: { + userId: userIdNeeded, + } + }) + // console.log("completed test", completed) + if(!completed){ + res.status(404).send("Oops, you either haven't completed any exercises, or something went wrong, try refreshing and try again.") + } else { + res.status(202).send({ + exercisesCompleted: completed, + user: {...userInfo.dataValues} + }) + } + + } catch(error){ + next(error) + } + } +) + + + +module.exports = router \ No newline at end of file diff --git a/routers/exercisesRouter.js b/routers/exercisesRouter.js new file mode 100644 index 0000000..46e248e --- /dev/null +++ b/routers/exercisesRouter.js @@ -0,0 +1,249 @@ +const { Router } = require("express") +const authMiddleware = require("../auth/middleware") + +const User = require("../models").user +const Exercises = require("../models").exercise +const CompletedExercises = require("../models").completedExercise +const QuizQuestions = require("../models").quizQuestion +const CompletedQuizzes = require("../models").completedQuiz + +const router = new Router() + +router.get( + "/:id/fastest", + async(req, res, next) => { + const exerciseIdNeeded = parseInt(req.params.id) + // console.log("exercise id test", exerciseIdNeeded) + if(!exerciseIdNeeded){ + res.status(400).send("Url malfunctioned, please refresh and try again.") + } + try{ + const exercisesCompleted = await CompletedExercises.findAll({ + where: { + exerciseId: exerciseIdNeeded, + } + }) + // console.log("completed exercises test", exercisesCompleted) + if(!exercisesCompleted){ + res.status(404).send("Oops it seems we couldnt find the completed exercises, refresh and try again.") + } + + const sortedExercisesCompleted = exercisesCompleted.sort((a, b) => { + const timeTakenA = a.timeTaken + // console.log(timeTakenA) + const timeTakenB = b.timeTaken + // console.log(timeTakenB) + if(timeTakenB > timeTakenA){ + return -1 + } else if(timeTakenA > timeTakenB){ + return 1 + } else { + return 0 + } + }) + // console.log("sorted exercises completed", sortedExercisesCompleted) + if(!sortedExercisesCompleted){ + res.status(400).send("Malfunction in the backend, refresh and try again.") + } else { + res.status(202).send(sortedExercisesCompleted) + } + + } catch(error){ + next(error) + } + } +) + +router.patch( + "/:id/quiz/completed", + authMiddleware, + async(req, res, next) => { + const userIdNeeded = req.user.id + // console.log("user ID test", userIdNeeded) + if(!userIdNeeded){ + res.status(401).send("Sorry you aren't authorized, please login/sign-up to authorize yourself.") + } + + const quizIdNeeded = parseInt(req.params.id) + // console.log("quiz ID test", quizIdNeeded) + if(!quizIdNeeded){ + res.status(400).send("The Url malfunctioned please refresh and try again.") + } + + try{ + const quizComplete = await CompletedQuizzes.create({ + userId: userIdNeeded, + quizQuestionId: quizIdNeeded, + exp: 10, + }) + console.log("created quiz test", quizComplete) + if(!quizComplete){ + res.status(404).send("Your info couldnt be processed, refresh and try again.") + } + + const userFound = await User.findByPk(userIdNeeded) + if(!userFound){ + res.status(404).send("Oops, we seem to be lost please login/sign-up so we can find you.") + } + + const updateExpUser = await userFound.increment("totalExp", { by: 10}) + // console.log("exp update test", updateExpUser) + if(!updateExpUser){ + res.status(400).send("Your exp wasnt updated please refresh and try again.") + } else { + delete updateExpUser.dataValues["password"] + res.status(202).send({ + user: {...updateExpUser.dataValues}, + completedQuiz: quizComplete, + }) + } + + + } catch(error){ + next(error) + } + } +) + +router.patch( + "/:id/completed", + authMiddleware, + async(req, res, next) => { + const userIdNeeded = req.user.id + // console.log("user id test:", userIdNeeded) + if(!userIdNeeded){ + res.status(401).send("Sorry you're not suppose to be here, please login in or sign up to continue.") + } + + const exerciseIdNeeded = parseInt(req.params.id) + // console.log("exercise Id test", exerciseIdNeeded) + if(!exerciseIdNeeded){ + res.status(400).send("The Url malfunctioned please refresh and try again.") + } + + const time = req.body.timeTaken + const expInt = parseInt(req.body.exp) + // console.log(`time test: ${time} + // exp test: ${expInt}`) + if(!time || !expInt){ + res.status(400).send("Please provide the proper credentials to continue.") + } + + try{ + const exerciseDone = await CompletedExercises.findOne({ + where: { + userId: userIdNeeded, + exerciseId: exerciseIdNeeded, + } + }) + ? + await CompletedExercises.update({ + timeTaken: time, + exp: expInt, + },{ + where: { + userId: userIdNeeded, + exerciseId: exerciseIdNeeded + } + }) + : + await CompletedExercises.create({ + userId: userIdNeeded, + exerciseId: exerciseIdNeeded, + timeTaken: time, + exp: expInt, + }) + if(!exerciseDone){ + res.status(404).send("We couldn't find you're completed exercises, please refresh and try again.") + } + + const sendExercise = await CompletedExercises.findOne({ + where: { + userId: userIdNeeded, + exerciseId: exerciseIdNeeded, + exp: expInt, + timeTaken: time, + } + }) + if(!sendExercise){ + res.status(404).send("We couldn't find you're completed exercises, please refresh and try again.") + } + + const userFound = await User.findByPk(userIdNeeded) + if(!userFound){ + res.status(404).send("Oops, we seem to be lost please login/sign-up so we can find you.") + } + + const updateUser = await userFound.increment("totalExp", { by: expInt}) + if(!updateUser){ + res.status(400).send("Oops, it seems yuor exp hasnt updated please refresh and try again.") + } else { + delete updateUser.dataValues["password"] + res.status(202).send({ + user: {...updateUser.dataValues}, + completed: sendExercise, + }) + } + + } catch(error){ + next(error) + } + } +) + +router.get( + "/:id/quiz", + authMiddleware, + async(req, res, next) => { + + if(!req.user){ + res.status(401).send("Sorry you aren't authorized, please login/sign-up to authorize yourself.") + } + + const exerciseIdNeeded = parseInt(req.params.id) + // console.log("questions ID test", exerciseIdNeeded) + if(!exerciseIdNeeded){ + res.status(400).send("Url malfunctioned, please refresh and try again.") + } + + try{ + const fecthQuizzes = await QuizQuestions.findAll({ + where: { + exerciseId: exerciseIdNeeded, + } + }) + // console.log("fetced quiz questions", fecthQuizzes) + if(!fecthQuizzes){ + res.status(404).send("It seems our quizzes have vanished, give us a moment will we find them. Refresh to help us.") + } else { + res.status(202).send(fecthQuizzes) + } + + } catch(error){ + next(error) + } + } +) + +router.get( + "/list", + authMiddleware, + async(req, res, next) => { + try{ + const exercisesList = await Exercises.findAll() + // console.log("exercises test", exercisesList) + + if(!exercisesList){ + res.status(404).send("Oops, exercises werent found, might be the server, we are working on it.") + } else { + res.status(202).send(exercisesList) + } + + } catch(error){ + next(error) + } + } +) + + +module.exports = router \ No newline at end of file diff --git a/seeders/20200318212758-users.js b/seeders/0-users.js similarity index 63% rename from seeders/20200318212758-users.js rename to seeders/0-users.js index fe755ae..d375ec2 100644 --- a/seeders/20200318212758-users.js +++ b/seeders/0-users.js @@ -8,16 +8,22 @@ module.exports = { "users", [ { - name: "testuser", + fullName: "testuser", + image: "https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcS107CDBZ5T8vEcN6nhUbhOp2xngySEndTw_g&usqp=CAU", email: "test@test.com", password: bcrypt.hashSync("test1234", SALT_ROUNDS), + ranking: "Code Monkey", + totalExp: 60, createdAt: new Date(), updatedAt: new Date(), }, { - name: "dummy", + fullName: "dummy", + image: "https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcS107CDBZ5T8vEcN6nhUbhOp2xngySEndTw_g&usqp=CAU", email: "a@a.com", password: bcrypt.hashSync("a", SALT_ROUNDS), + ranking: "Code Monkey", + totalExp: 50, createdAt: new Date(), updatedAt: new Date(), }, diff --git a/seeders/1-some-exercises.js b/seeders/1-some-exercises.js new file mode 100644 index 0000000..5ce1729 --- /dev/null +++ b/seeders/1-some-exercises.js @@ -0,0 +1,72 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert( + 'exercises', [ + { + name: "Map method", + content: `The map() method creates a new array with the results of calling a function for every array element. + The map() method calls the provided function once for each element in an array, in order. + Note: map() does not execute the function for array elements without values.`, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: "Filter method", + content: `The filter() method creates an array filled with all array elements that pass a test (provided as a function). + Note: filter() does not execute the function for array elements without values. Note: filter() does not change the original array.`, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: "Find method", + content: `If it finds an array element where the function returns a true value, find() returns the value of that array element (and does not check the remaining values). + Otherwise it returns undefined.`, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: "Pop method", + content: `The pop method removes the last element from an array and returns that value to the caller. + Pop is intentionally generic; this method can be called or applied to objects resembling arrays.`, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: "Push method", + content: `The push() method adds new items to the end of an array, and returns the new length. + Note: The new item(s) will be added at the end of the array. Note: This method changes the length of the array.`, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: "Shift method", + content: `The shift method removes the element at the zeroeth index and shifts the values at consecutive indexes down, + then returns the removed value. + If the length property is 0, undefined is returned. shift is intentionally generic; this method can be called or applied to objects resembling arrays.`, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: "unShift method", + content: `The unshift() method adds new items to the beginning of an array, and returns the new length. + Note: This method changes the length of an array.`, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + name: "Sort Method", + content: `The sort() method sorts the items of an array. + The sort order can be either alphabetic or numeric, and either ascending (up) or descending (down). + By default, the sort() method sorts the values as strings in alphabetical and ascending order.`, + createdAt: new Date(), + updatedAt: new Date(), + } + ] + )}, + + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('exercises', null, {}); + } +}; diff --git a/seeders/2-some-completedExercises.js b/seeders/2-some-completedExercises.js new file mode 100644 index 0000000..fa2101e --- /dev/null +++ b/seeders/2-some-completedExercises.js @@ -0,0 +1,38 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert( + 'completedExercises', [ + { + userId: 1, + exerciseId: 3, + timeTaken: "00:05:00", + exp: 40, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + userId: 1, + exerciseId: 2, + timeTaken: "00:15:00", + exp: 20, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + userId: 2, + exerciseId: 1, + timeTaken: "00:02:35", + exp: 50, + createdAt: new Date(), + updatedAt: new Date(), + } + ] + + )}, + + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('completedExercises', null, {}); + } +}; diff --git a/seeders/3-some-quizQuestions.js b/seeders/3-some-quizQuestions.js new file mode 100644 index 0000000..bc68f66 --- /dev/null +++ b/seeders/3-some-quizQuestions.js @@ -0,0 +1,304 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert( + 'quizQuestions', [ + { + question: "What does the Map() accomplish?", + answer: "Creates a new array populated with the results of calling a provided function on every element in the calling array.", + incorrect1: "Calls a provided callback function once for each element in the array, that transforms the old array.", + incorrect2: "It calls for all elements of the array including the missing elements and creates a new array with the results.", + incorrect3: "Populates the original array with the results of calling a provided function on every element in the calling array.", + exerciseId: 1, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "Which of these answers uses the correct syntax for the Map()", + answer: "array.map( x => x * a)", + incorrect1: "array.map(x * a)", + incorrect2: "array.map(() = x => x * a)", + incorrect3: "array.map(x = x * a)", + exerciseId: 1, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "What does the Filter() accomplish?", + answer: "filters the data in the array according to a condition", + incorrect1: "filters the data in the array and always returns one", + incorrect2: "filters the data in the array and returns the index of all", + incorrect3: "filters the data and removes elements of the array according to a condition.", + exerciseId: 2, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `What is the outcome of the following code? + const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']; + const result = words.filter(word => word.length > 6);`, + answer: "Array ['exuberant', 'destruction', 'present’]", + incorrect1: 'Array ["present"]', + incorrect2: "Array [spray, limit, elite, exuberant, destruction, present]", + incorrect3: "Array [exuberant, destruction, present]", + exerciseId: 2, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "What does the Find() accomplish?", + answer: "returns the first element in the array that fits the condition", + incorrect1: "returns all the elements in the array that fit the condition", + incorrect2: "finds the correct spot in the array so you can add an element in there.", + incorrect3: "returns the last element in the array that fits the condition", + exerciseId: 3, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `What is the outcome of the following code? + const numberOfMonkeys = [ 3, 12, 8, 35, 15 ] + const result = numberOfMonkeys.find(monkeys => monkeys > 10)`, + answer: "12", + incorrect1: "12, 35, 15", + incorrect2: "12, 8, 35, 15", + incorrect3: "none of the above ", + exerciseId: 3, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "What does the Pop() accomplish?", + answer: "Removes the last item from an array and returns it. ", + incorrect1: "removes all of the items in the array", + incorrect2: "adds an item to the end of an array and returns the array.", + incorrect3: "removes the first item from an array and returns it.", + exerciseId: 4, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `What is the expected output of the following code? + const kings = [“King Arthur”, “Queen Elizabeth”, "King Willem Alexander”, “The Monkey King”] + console.log(kings.pop())`, + answer: "The Monkey King", + incorrect1: "King Arthur", + incorrect2: '[“King Arthur”, “Queen Elizabeth”, "King Willem Alexander”]', + incorrect3: '[“Queen Elizabeth”, "King Willem Alexander”, “The Monkey King”]', + exerciseId: 4, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "What does the Push() accomplish?", + answer: "The push() method adds new items to the end of an array", + incorrect1: "The push() method replaces items at the end of an array", + incorrect2: "The push() method removes the first items of the array", + incorrect3: "The push() method removes items at the end of an array.", + exerciseId: 5, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `What is the outcome of the following code? + let sports = ['soccer', 'baseball']; + let total = sports.push('football', 'swimming'); + console.log(sports`, + answer: " ['soccer', 'baseball', 'football', 'swimming']", + incorrect1: " ['soccer', 'baseball']", + incorrect2: "['football', 'swimming']", + incorrect3: "['football', 'swimming', 'soccer', 'baseball']", + exerciseId: 5, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "What does the Shift() accomplish?", + answer: "The shift() method removes the first item of an array", + incorrect1: "The shift() method adds an item to the beginning of an array", + incorrect2: "The shift() method removes the last item of an array", + incorrect3: "The shift() method replaces the last item of an array", + exerciseId: 6, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `What is the outcome of the following code? + let animals = ["Macaque", "Baboon", "Gorilla", "Orangutan"]; + animals.shift();`, + answer: '["Baboon", "Gorilla", "Orangutan"]', + incorrect1: '["Macaque", "Baboon", "Gorilla"]', + incorrect2: '["Orangutan", "Baboon", "Gorilla", "Macaque"]', + incorrect3: '["Gorilla", "Orangutan"]', + exerciseId: 6, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "What does the unShift() accomplish?", + answer: "The unshift() method adds new items to the beginning of an array", + incorrect1: "The unshift() method removes the first items of an array", + incorrect2: "The unshift() method adds new items to the end of an array", + incorrect3: "The unshift() method removes the last items of an array", + exerciseId: 7, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `What is the outcome of the following code? + let jungle = ['Monkey', 'Tiger', 'Bird']; + jungle.unshift('Snake', ‘Elephant’, ‘Hippo’)`, + answer: "[‘Snake’, ‘Elephant’, ‘Hippo’, ‘Monkey’, ‘Tiger’, ‘Bird’]", + incorrect1: "['Monkey', 'Tiger', 'Bird']", + incorrect2: "[‘Snake’, ‘Elephant’, ‘Hippo’]", + incorrect3: "['Monkey', 'Tiger', 'Bird', ‘Snake’, ‘Elephant’, ‘Hippo’]", + exerciseId: 7, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: "What does the Sort() accomplish?", + answer: "all of the above", + incorrect1: "By default, the sort() function sorts values as strings", + incorrect2: "To sort() numbers you need to add a compare function", + incorrect3: "By default, the sort() function sorts values as strings", + exerciseId: 8, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `What is the outcome of the following code? + let numberOfBananas = [40, 100, 1, 5, 25, 10]; + numberOfBananas.sort(function(a, b){return a - b});`, + answer: "1, 5, 10, 25, 40, 100", + incorrect1: "100, 40, 25, 10, 5, 1", + incorrect2: "1, 10, 100, 25, 40, 5", + incorrect3: "5, 40, 25, 100, 10, 1", + exerciseId: 8, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + Sort the age of the monkeys from oldest to youngest. + const ageMonkeys = [50, 3, 23, 12, 1]; + answer = [50,3,23,12,1]`, + answer: "ageMonkeys.sort(function(a, b){return b - a})", + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 8, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + Fill in the console.logs so the expected output is correct. + const numbers = [1, 2, 3] + console.log(YOU"RE ANSWER) + answer = 5 + console.log(YOU"RE ANSWER) + answer = [4,5,1,2,3]`, + answer: "[numbers.unshift(4, 5), numbers)]", + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 7, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + Use the .shift() method to get “Banana” out of the console.log + let fruits = ["Banana", "Orange", "Apple", "Mango"]; + answer = "Banana"`, + answer: "fruits.shift()", + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 6, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + There are 2 monkeys in the jungle; Rafiki and King Louie. + Abu, who is 15 years old, wants to join. change the following code so Abu will be added to the list of monkeys in the jungle. + let monkeys = [ + { + name: 'Rafiki', + age: 96 + }, + { + name: 'King Louie', + age: 50 + } + ]; + + // your code here + + console.log(monkeys)`, + answer: "fruits.shift()", + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 5, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + Use the map function to double all of the numbers in the array. + const array = [1,2,3,4]`, + answer: "const answer = array.map(item => item * 2)", + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 1, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + Monkeys love bananas! And hate broccoli! Please use filter to get only the bananas out of the array. + const food = [“banana", “broccoli”, “banana”, “broccoli”, “banana”, “broccoli”]`, + answer: `const answer = food.filter(item => item === “banana”`, + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 2, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + How many monkeys do we need to unscrew a light bulb? - more than 5 apparently- Please get us more than 5 monkeys out of the array. + const numberOfMonkeys= [3, 5, 7, 2, 9]`, + answer: `const answer = numberOfMonkeys.find(item => item > 5)`, + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 3, + createdAt: new Date(), + updatedAt: new Date(), + }, + { + question: `Open Question? + Monkey Popo has levelled up his skills and now finally has become a Code Master! Please remove his name from the list of code monkeys! + const listOfMonkeys = [“Rafiki”, “Bubbles”, “Curious George”, “Popo"]`, + answer: `console.log(listOfMonkeys.pop())`, + incorrect1: "Only one", + incorrect2: "Only one", + incorrect3: "Only one", + exerciseId: 4, + createdAt: new Date(), + updatedAt: new Date(), + } + ] + )}, + + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('quizQuestions', null, {}); + } +}; diff --git a/seeders/4-some-completedQuiz.js b/seeders/4-some-completedQuiz.js new file mode 100644 index 0000000..1f73441 --- /dev/null +++ b/seeders/4-some-completedQuiz.js @@ -0,0 +1,20 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.bulkInsert( + 'completedQuizzes', [ + { + userId: 1, + quizQuestionId: 1, + exp: 10, + createdAt: new Date(), + updatedAt: new Date(), + } + ] + )}, + + down: async (queryInterface, Sequelize) => { + await queryInterface.bulkDelete('completedQuizzes', null, {}); + } +};